如何无需重复指定返回值,仅传入函数调用非类型模板参数的函数模板?
无需预处理器实现
Call<f>()的调用方式 当然可以实现!不用依赖预处理器宏,我们可以借助C++17及以后的语言特性来简化这个调用,下面是最简洁的解决方案:
利用C++17的auto非类型模板参数
C++17引入了auto非类型模板参数,允许编译器自动推导非类型模板参数的类型,结合返回值类型推导,我们可以直接写出不需要手动指定返回值的模板:
template <auto Func> auto Call() { return Func(); } // 测试代码 int f() { return 1; } double g() { return 3.14; } int main() { Call<f>(); // 正常编译,返回int类型的1 Call<g>(); // 正常编译,返回double类型的3.14 }
原理说明
- 这里的
auto Func让编译器自动推导传入的函数f/g的类型(比如f的类型是int(*)()),不需要我们显式声明函数的返回值或类型。 - 返回值的
auto会自动推导Func()的返回类型,完美替代了原来需要手动指定的R参数。
兼容C11/14的替代方案(如果不能用C17)
如果你的环境还停留在C11或C14,虽然没有auto非类型模板参数,但可以通过decltype推导返回值,只是调用时需要多写一点:
template <typename FuncType, FuncType Func> auto Call() -> decltype(Func()) { return Func(); } int main() { Call<decltype(f), f>(); // 编译正常,利用decltype推导函数类型 }
不过这种写法还是比C17的版本繁琐,所以优先推荐C17及以上的方案。
为什么原代码的Call<f>()会报错?
你原来的模板是先声明返回值类型R,再声明函数参数func,模板参数的推导是按顺序进行的——编译器无法从后面的f推导出前面的R,所以必须显式指定R才能编译。而新的方案通过让编译器自动推导参数类型和返回值,避免了这个问题。
内容的提问来源于stack exchange,提问作者M.M
相关产品推荐
相关产品推荐

