从重载函数中提取返回类型
我想提取函数的返回类型。问题是,还有其他具有相同名称但不同签名的函数,我无法让 C++ 选择合适的函数。我了解 std::result_of,但经过几次尝试,我得出结论,它也遇到了同样的问题。我也听说过涉及 decltype 的解决方案,但我不知道任何细节。
目前,我正在使用模板元编程从函数指针类型中提取返回类型,这对于有限数量的参数(任何非限制解决方案?)来说效果很好,因为函数指针类型的提取适用于明确的函数。
#include <iostream>
using namespace std;
// ----
#define resultof(x) typename ResultOf<typeof(x)>::Type // might need a & before x
template <class T>
class ResultOf
{
public:
typedef void Type; // might need to be T instead of void; see below
};
template <class R>
class ResultOf<R (*) ()>
{
public:
typedef R Type;
};
template <class R, class P>
class ResultOf<R (*) (P)>
{
public:
typedef R Type;
};
// ----
class NoDefaultConstructor
{
public:
NoDefaultConstructor (int) {}
};
int f ();
int f ()
{
cout << "f" << endl;
return 1;
}
double f (int x);
double f (int x)
{
cout << "f(int)" << endl;
return x + 2.0;
}
bool f (NoDefaultConstructor);
bool f (NoDefaultConstructor)
{
cout << "f(const NoDefaultConstructor)" << endl;
return false;
}
int g ();
int g ()
{
cout << "g" << endl;
return 4;
}
int main (int argc, char* argv[])
{
if(argc||argv){}
// this works since there is no ambiguity. does not work without &
// resultof(&g) x0 = 1;
// cout << x0 << endl;
// does not work since type of f is unknown due to ambiguity. same thing without &
// resultof(&f) x1 = 1;
// cout << x1 << endl;
// does not work since typeof(f()) is int, not a member function pointer; we COULD use T instead of void in the unspecialized class template to make it work. same thing with &
// resultof(f()) x2 = 1;
// cout << x2 << endl;
// does not work per above, and compiler thinks differently from a human about f(int); no idea how to make it correct
// resultof(f(int)) x3 = 1;
// cout << x3 << endl;
// does not work per case 2
// resultof(f(int())) x4 = 1;
// cout << x4 << endl;
// does not work per case 2, and due to the lack of a default constructor
// resultof(f(NoDefaultConstructor())) x5 = 1;
// cout << x5 << endl;
// this works but it does not solve the problem, we need to extract return type from a particular function, not a function type
// resultof(int(*)(int)) x6 = 1;
// cout << x6 << endl;
}
知道我缺少什么语法功能以及如何修复它,最好使用以简单方式工作的解决方案,例如 resultof(f(int))
?
I want to extract the return type of a function. Problem is, there are other functions with the same name but different signature, and I can not get C++ to select the appropriate one. I know about std::result_of, but from a few tries I have concluded it suffers from the same problem as well. I have heard about a solution involving decltype as well, but I do not know any specifics.
At the moment I am using template metaprogramming to extract the return type from a function pointer type, which works fine for a limited number of parameters (any non-limited solution?), given that extraction of function pointer type works for unambiguous functions.
#include <iostream>
using namespace std;
// ----
#define resultof(x) typename ResultOf<typeof(x)>::Type // might need a & before x
template <class T>
class ResultOf
{
public:
typedef void Type; // might need to be T instead of void; see below
};
template <class R>
class ResultOf<R (*) ()>
{
public:
typedef R Type;
};
template <class R, class P>
class ResultOf<R (*) (P)>
{
public:
typedef R Type;
};
// ----
class NoDefaultConstructor
{
public:
NoDefaultConstructor (int) {}
};
int f ();
int f ()
{
cout << "f" << endl;
return 1;
}
double f (int x);
double f (int x)
{
cout << "f(int)" << endl;
return x + 2.0;
}
bool f (NoDefaultConstructor);
bool f (NoDefaultConstructor)
{
cout << "f(const NoDefaultConstructor)" << endl;
return false;
}
int g ();
int g ()
{
cout << "g" << endl;
return 4;
}
int main (int argc, char* argv[])
{
if(argc||argv){}
// this works since there is no ambiguity. does not work without &
// resultof(&g) x0 = 1;
// cout << x0 << endl;
// does not work since type of f is unknown due to ambiguity. same thing without &
// resultof(&f) x1 = 1;
// cout << x1 << endl;
// does not work since typeof(f()) is int, not a member function pointer; we COULD use T instead of void in the unspecialized class template to make it work. same thing with &
// resultof(f()) x2 = 1;
// cout << x2 << endl;
// does not work per above, and compiler thinks differently from a human about f(int); no idea how to make it correct
// resultof(f(int)) x3 = 1;
// cout << x3 << endl;
// does not work per case 2
// resultof(f(int())) x4 = 1;
// cout << x4 << endl;
// does not work per case 2, and due to the lack of a default constructor
// resultof(f(NoDefaultConstructor())) x5 = 1;
// cout << x5 << endl;
// this works but it does not solve the problem, we need to extract return type from a particular function, not a function type
// resultof(int(*)(int)) x6 = 1;
// cout << x6 << endl;
}
Any idea what syntax feature am I missing and how to fix it, preferably with a solution that works in a simple way, e.g. resultof(f(int))
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为这可以通过
decltype
和declval
来完成:例如:
decltype(f(std::declval()))
。I think that this can be done with
decltype
anddeclval
:For example:
decltype(f(std::declval<T>()))
.在没有参数的情况下检查重载函数名称非常困难。您可以检查返回类型是否有不同数量的重载——前提是没有一个数量具有多个重载。即便如此,将硬错误(如果/当给定的数量确实有多个重载时)转换为 SFINAE 也是一种痛苦,因为它需要仅为该特定函数编写一个特征(!),因为重载的函数名称不能作为传递任何形式的争论。可能还需要用户代码使用显式专业化...
鉴于您使用的是 C++0x,我觉得有必要指出(IMO)永远不需要检查
之外的返回类型typename std::result_of::type
,这不适用于函数名称;但也许你对此的兴趣纯粹是学术上的。It's very hard to inspect an overloaded function name without arguments. You can inspect the return types for overloads that differ in arity -- provided that no arity has more than one overload. Even then, turning a hard error (if/when a given arity does have more than one overload) into SFINAE is a pain as it requires writing a trait just for that particular function(!) since overloaded function names can't be passed as any kind of argument. Might as well require user code to use an explicit specialization...
Given that you're using C++0x, I feel the need to point out that there is (IMO) never a need to inspect a return type beyond
typename std::result_of<Functor(Args...)>::type
, and that doesn't apply to function names; but perhaps your interest in this is purely academical.好的,经过几次尝试,我设法解决了 Mankarse 建议的 std::declval 方法。我使用可变参数类模板来固定参数,并使用函数的模板推导从函数指针获取返回值。它当前的语法是
typeof(ResultOf::get(function))
,不幸的是,它距离所需的resultof(function)
形式还很远。如果我找到进一步简化它的方法,将编辑这个答案。编辑:
设法用可变参数宏解决它,语法现在是
resultof(f, param1, param2, etc)
。没有它们,我无法将参数类型之间的逗号传递给模板。尝试使用语法resultof(f, (param1, param2, etc))
无济于事。Okay, after a few attempts I managed to work around the
std::declval
method suggested by Mankarse. I used a variadic class template to fixate the parameters, and used the template deduction of functions to get the return value from a function pointer. Its current syntax istypeof(ResultOf<parameters>::get(function))
, unfortunately it is still far from the desiredresultof<parameters>(function)
form. Will edit this answer if I find a way to further simplify it.Edit:
Managed to solve it with variadic macros, the syntax is now
resultof(f, param1, param2, etc)
. Without them I couldn't pass the commas between the parameter types to the template. Tried with the syntaxresultof(f, (param1, param2, etc))
to no avail.