【发布时间】:2017-02-13 07:47:42
【问题描述】:
我正在尝试使用 SFINAE 创建函数调用包装器,使用 std::result_of 来获取函数的返回类型。重现问题的小样本:
void test(int) {}
template<typename T, typename... Args, typename R = typename std::result_of<T(Args...)>::type, typename std::enable_if<!std::is_void<R>::value, int>::type* = nullptr>
int test2(R& ret_param, Args... args)
{
T* test_call = test;
ret_param = test_call(args...);
return 0;
}
template<typename T, typename... Args, typename std::enable_if<std::is_void<typename std::result_of<T(Args...)>::type>::value, int>::type* = nullptr>
int test2(Args... args)
{
T* test_call = test;
test_call(args...);
return 0;
}
int main()
{
test2<decltype(test)>(1);
}
用 gcc 4.9.2 编译它会导致:
68:26: error: no matching function for call to 'test2(int)'
68:26: note: candidates are:
46:5: note: int test2(R&, Args ...) [with T = void(int); Args = {}; R = int; typename std::enable_if<(! std::is_void<R>::value), int>::type* <anonymous> = 0u]
46:5: note: no known conversion for argument 1 from 'int' to 'int&'
56:5: note: template<class T, class ... Args, typename std::enable_if<std::is_void<typename std::result_of<_Functor(_ArgTypes ...)>::type>::value, int>::type* <anonymous> > int test2(Args ...)
56:5: note: template argument deduction/substitution failed:
55:142: error: function returning a function
55:142: note: invalid template non-type parameter
那么问题是“typename std::result_of::type”以某种方式计算为返回函数的函数?如果模板函数的返回类型为 void,使用 SFINAE 强制重载决议选择不同函数的正确方法是什么?值得一提的是,在测试函数返回 int 的相反情况下。此外,如果为 std::is_void 解析删除了 enable_if ,它将在这种情况下工作(但显然,如果有返回类型,那么这两个函数都是有效的解析,并且当它选择不期望返回值的那个时编译将失败)。
【问题讨论】:
-
首先,
decltype(test)是一个函数类型,您将其绑定到T,在启用逻辑中它被视为返回类型。 -
我会使用
class而不是typename,我会避免使用那些数百个字符的行。尝试自然地拆分内容以便于阅读。 -
不跟随,我的理解是 std::result_of
::type 是函数 T 的返回类型,如果使用参数 Args... 调用它是我在启用逻辑中使用的内容。 -
T(Args...),例如int(char, double),是一个返回T并带有形式参数Args...的函数。等一下。std::result_of被定义为期望这一点。对不起。 -
好吧,对不起“对不起”:您需要形成 T_ref(Args...),其中 T_ref 是 T&。请参阅
std::result_of要求。
标签: c++ c++11 variadic-templates sfinae