是否可以在编译时获取模板成员函数的返回类型?
我想我需要的是:
template<class T>
struct SomeClass
{
// T must have a function foo(int), but do not know the
// return type, it could be anything
using RType = ??? T::foo(int) ???; // Is it possible to deduce it here?
}
答案 0 :(得分:2)
使用decltype
运算符和std::declval
模板可以实现您想要做的事。
decltype(EXPRESSION)
在编译时产生EXPRESSION
所具有的类型。永远不会评估EXPRESSION
本身。这很像sizeof(EXPRESSION)
返回任何EXPRESSION
求值的大小而没有实际评估它。
只有一个问题:您的foo
是非static
成员函数,因此编写decltype(T::foo(1))
是一个错误。我们需要获得T
的实例。即使我们对它的构造函数一无所知,我们也可以使用std::declval
来获取对它的实例的引用。这是纯粹的编译时间。 std::declval
实际上从未被定义(仅被声明),因此不要尝试在运行时对其进行评估。
以下是它们的组合方式。
#include <type_traits>
template <typename SomeT>
struct Something
{
using RetT = decltype(std::declval<SomeT>().foo(1));
};
要了解它确实有效,请考虑此示例。
struct Bar
{
float
foo(int);
};
struct Baz
{
void
foo(int);
};
int
main()
{
static_assert(std::is_same<float, Something<Bar>::RetT>::value, "");
static_assert(std::is_same<void, Something<Baz>::RetT>::value, "");
}
虽然这就是我认为你所要求的,但是如果你试图用Something<T>
实例化T
而不是拥有一个合适的foo
成员,你会得到一个硬编译错误。最好将类型计算移动到模板参数中,以便您可以从SFINAE规则中受益。
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};
答案 1 :(得分:0)
如果您知道函数调用的参数类型,则以下内容应该有效:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
如果不这样做,您仍然可以推断出函数指针的类型并提取返回类型:
template<class F>
struct return_type;
template<class C, class R, class... Args>
struct return_type<R(C::*)(Args...)>
{ using type = R; };
template<typename T>
struct X
{
typedef typename return_type<decltype(&T::foo)>::type type;
};
如果T::foo
是重载函数或T
成员,则会失败。
不幸的是,如果你知道你将要调用它的哪个参数(不幸的是,通常与你需要知道返回类型的位置不同),只能知道某个表达式的返回类型。