模板成员函数的编译时间推导
Compile time deduction of template member function
是否可以在编译时获取模板成员函数的return类型?
我想我需要一些类似的东西:
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?
}
如果您知道函数调用的参数类型,则以下方法应该有效:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
如果你不这样做,你仍然可以推断出函数指针的类型并提取 return 类型:
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
的成员,这将失败。
不幸的是,如果你知道你将用什么参数调用它,那么只有知道某些表达式的 return 类型才有可能(不幸的是,这通常与你需要知道的地方不同return 类型)...
使用decltype
operator together with the std::declval
模板可以实现您想做的事情。
decltype(<i>EXPRESSION</i>)
在编译时产生 <i>EXPRESSION</i>
会有。 <i>EXPRESSION</i>
本身永远不会被评估。这很像 sizeof(<i>EXPRESSION</i>)
returns <i>EXPRESSION</i>
计算为 to 但从未实际计算过它。
只有一个问题:您的 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, "");
}
虽然这符合我认为您的要求,但如果您尝试使用 T
实例化 Something<T>
而不是 有 一个合适的 foo
成员,你会得到一个硬编译器错误。最好将类型计算移动到模板参数中,这样您就可以从 SFINAE 规则中受益。
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};
是否可以在编译时获取模板成员函数的return类型?
我想我需要一些类似的东西:
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?
}
如果您知道函数调用的参数类型,则以下方法应该有效:
template<typename T>
struct X
{
typedef typename decltype(std::declval<T>.foo(std::declval<int>())) type;
};
如果你不这样做,你仍然可以推断出函数指针的类型并提取 return 类型:
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
的成员,这将失败。
不幸的是,如果你知道你将用什么参数调用它,那么只有知道某些表达式的 return 类型才有可能(不幸的是,这通常与你需要知道的地方不同return 类型)...
使用decltype
operator together with the std::declval
模板可以实现您想做的事情。
decltype(<i>EXPRESSION</i>)
在编译时产生 <i>EXPRESSION</i>
会有。 <i>EXPRESSION</i>
本身永远不会被评估。这很像 sizeof(<i>EXPRESSION</i>)
returns <i>EXPRESSION</i>
计算为 to 但从未实际计算过它。
只有一个问题:您的 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, "");
}
虽然这符合我认为您的要求,但如果您尝试使用 T
实例化 Something<T>
而不是 有 一个合适的 foo
成员,你会得到一个硬编译器错误。最好将类型计算移动到模板参数中,这样您就可以从 SFINAE 规则中受益。
template <typename SomeT,
typename RetT = decltype(std::declval<SomeT>().foo(1))>
struct Something
{
// Can use RetT here ...
};