实现可调用对象返回类型提取Trait时的SFINAE错误排查
问题:SFINAE实现可调用对象返回类型提取失败
背景
我正在练习SFINAE技术,尝试获取各类可调用对象(函数、函数指针、lambda、重载()运算符的对象)的相关信息,编写了如下代码:
#include <iostream> #include <functional> #include <string> #include <type_traits> template<typename Callable, typename = void> struct function_type_info; template<typename R, typename G, typename... T> struct function_type_info<R(G::*)(T...)> { using return_type = R; }; template<typename C> struct function_type_info<C, typename std::enable_if<!std::is_member_function_pointer<C>::value, C>::type> { using return_type = typename function_type_info<decltype(&C::operator())>::return_type; }; struct Callback { int operator()(double, std::string) { return 0; } }; int main(int argc, char** argv) { auto b = [](double, std::string) -> int { return 0; }; auto c = Callback{}; std::cout << std::boolalpha; std::cout << std::is_same<function_type_info<decltype(&Callback::operator())>::return_type, int>::value << std::endl; std::cout << std::is_same<function_type_info<decltype(b)>::return_type, int>::value << std::endl; std::cout << std::is_same<function_type_info<decltype(c)>::return_type, int>::value << std::endl; return 0; }
初始编译错误
编译器报出如下错误:
<source>:32:64: error: incomplete type 'function_type_info<main(int, char**)::<lambda(double, std::string)> >' used in nested name specifier 32 | std::cout << std::is_same<function_type_info<decltype(b)>::return_type, int>::value << std::endl; | ^~~~~~~~~~~ <source>:32:80: error: template argument 1 is invalid 32 | std::cout << std::is_same<function_type_info<decltype(b)>::return_type, int>::value << std::endl; | ^ <source>:33:64: error: incomplete type 'function_type_info<Callback>' used in nested name specifier 33 | std::cout << std::is_same<function_type_info<decltype(c)>::return_type, int>::value << std::endl; | ^~~~~~~~~~~ <source>:33:80: error: template argument 1 is invalid 33 | std::cout << std::is_same<function_type_info<decltype(c)>::return_type, int>::value << std::endl;
调试后的问题
我无法理解错误原因:对于lambda和Callback对象,第二个function_type_info特化应该被匹配,因为std::is_member_function_pointer<C>::value为false,enable_if应生效。将enable_if的第二个参数改为void后,Callback可以正常工作,但lambda仍报错,错误信息如下:
<source>: In instantiation of 'struct function_type_info<main(int, char**)::<lambda(double, std::string)> >': <source>:32:62: required from here <source>:16:11: error: invalid use of incomplete type 'struct function_type_info<int (main(int, char**)::<lambda(double, std::string)>::*)(double, std::__cxx11::basic_string<char>) const, void>' 16 | using return_type = typename function_type_info<decltype(&C::operator())>::return_type; | ^~~~~~~~~~~ <source>:7:8: note: declaration of 'struct function_type_info<int (main(int, char**)::<lambda(double, std::string)>::*)(double, std::__cxx11::basic_string<char>) const, void>' 7 | struct function_type_info; | ^~~~~~~~~~~~~~~~~~ <source>: In function 'int main(int, char**)': <source>:32:80: error: template argument 1 is invalid 32 | std::cout << std::is_same<function_type_info<decltype(b)>::return_type, int>::value << std::endl;
补充说明
仿佛无法访问lambda的()运算符。注:我知道可用std::result_of/std::invoke_result实现,但这是练习。
内容的提问来源于stack exchange,提问作者sunmat
相关产品推荐
相关产品推荐

