无需参数能否基于函数做类型推断?解决decltype参数要求问题
关于decltype推导函数返回类型的问题解答
1. 是否必须传入参数?背后的实际原因?
是的,在早期C标准(C11/14)的常规用法里,用decltype(f(...))推导返回类型时确实需要传参数,主要有两个实际原因:
- 语法层面的要求:
decltype的处理对象必须是合法表达式,单独的函数名f只是函数类型的左值,不算完整的表达式。只有写成f(args)这种函数调用表达式,decltype才能识别并推导其返回类型。 - 重载决议的需要:如果函数存在重载,仅靠函数名编译器根本不知道你要推导的是哪个版本的返回类型。必须通过参数的类型、数量来完成重载决议,锁定具体的函数——哪怕返回类型和参数没关系,这一步也是编译器确定目标函数的必要过程。
2. 无需传入人工参数的实现方法
有多种方法可以避免手动创建实际参数,不同C++版本的方案如下:
C++11及以上:用
std::declval模拟参数std::declval<T>()是标准库提供的工具,它可以在不构造对象的前提下生成一个T&&类型的右值引用,用来模拟函数调用的参数。比如对于函数int bar(std::string, MyStruct),可以这样推导返回类型:#include <utility> // 包含std::declval using ReturnType = decltype(bar(std::declval<std::string>(), std::declval<MyStruct>()));这种方法适用于所有可调用对象,哪怕参数类型是不可构造的(比如抽象类、无默认构造的类型)。
C++14及以上:用
std::result_of_t或std::invoke_result_t
C14引入的std::result_of_t<FuncType(ArgTypes...)>可以直接推导函数的返回类型,无需写调用表达式。C17之后推荐用更通用的std::invoke_result_t,它支持lambda、函数对象等所有可调用类型:#include <type_traits> // 包含result_of/invoke_result // 针对普通函数的例子 using ReturnType = std::invoke_result_t<decltype(&bar), std::string, MyStruct>; // 针对lambda的例子 auto lambda = [](int, bool) -> double { return 3.14; }; using LambdaRet = std::invoke_result_t<decltype(lambda), int, bool>; // 类型是double自定义模板提取返回类型(兼容全版本)
如果你需要兼容更早的C++版本,可以手动写一个简单的模板来提取函数类型的返回值:template<typename Func> struct GetReturnType; // 匹配普通函数 template<typename Ret, typename... Args> struct GetReturnType<Ret(Args...)> { using type = Ret; }; // 匹配函数指针 template<typename Ret, typename... Args> struct GetReturnType<Ret(*)(Args...)> { using type = Ret; }; // 使用方式 using ReturnType = GetReturnType<decltype(bar)>::type;
内容的提问来源于stack exchange,提问作者paxdiablo
相关产品推荐
相关产品推荐

