一段时间过去了,自提出问题以来现在的答案是可以的!
没错,问题标记为C++11 - 在此版本中仍不能做到OP所要求的。但值得一提的是,现在我们可以使用C++14或更高版本实现这个需求。
C++14开始,以下代码是有效的:
template<class A, class B>
auto sum(A a, B b) {
return a + b;
}
自C++20以来,这也是有效的:
auto sum(auto a, auto b) {
return a + b;
}
以下是C++11的答案,因为历史原因而保留,并附有一些来自未来(C++14及以后版本)的注释:
如果我们有以下内容:
template<class A, class B, class C>
auto sum(A a, B b, C c) {
if (rand () == 0) return a + b;
return a + c;
}
..其中a + b
和a + c
表达式产生不同类型的结果。
编译器应该决定将什么作为该函数的返回类型,以及为什么?
这种情况已经被C++11 lambda覆盖,只要return
语句可以被推导到相同的类型(需要注意的是标准引用,一些来源声称只允许一个返回表达式,并且这是gcc的故障)。
来自未来的注释(C++14及以上版本):上面的示例仍然无效,您只能拥有一个可能的返回类型。但是,如果有不同的返回类型,但实际返回类型可以在编译时推断出,则我们有两个不同的函数,这是有效的。例如,以下示例自C++17起是有效的:
template<class A, class B, class C>
auto sum(A a, B b, C c) {
if constexpr(std::is_same_v<A, B>) return a + b;
else return a + c;
}
int main() {
auto a1 = sum(1, 2l, 3.5);
auto a2 = sum(1, 2, 3.5);
}
回到原始的 C++11 答案,解释为什么不支持所请求的语法:
技术上的原因是 C++ 允许定义和声明分开。
template<class A, class B>
auto sum(A a, B b) -> decltype(a + b);
template<class A, class B>
auto sum(A a, B b) -> decltype(a + b)
{
}
模板的定义可以在头文件中,也可以在另一个文件中。这样,当查看接口时,您不必浏览页面和页面的函数定义。
C++必须考虑所有可能性。将尾随返回类型限制为函数定义意味着您无法执行像这样简单的操作:
template<class A, class B>
class Foo
{
auto sum(A a, B b) -> decltype(a + b);
}
template<class A, class B>
auto Foo<A, B>::sum(A a, B b) -> decltype(a + b)
{
}
来自未来的一条注释(C++14及以上版本):如果编译器在调用时没有看到定义,你仍然不能使用auto
返回类型进行声明。
decltype
的一个用例,而且这个问题没有涉及到其他任何用例。 - pmrauto foo(auto x, auto y) { return x + y;}
是很好的,而且肯定是可行的,但是使用额外的语法也可以做到,只是更烦人;烦恼比新规则更容易处理。话虽如此,他们没有详细说明推断返回类型对于诸如lambda之类的事情是极其不幸的。 - GManNickG-std=c++1y
选项即可。目前这个功能正在被提出。 - chris