为什么函数 return 类型不允许参数推导?

Why isn't argument deduction allowed in function return type?

最明显的答案可能是 - 因为标准是这么说的
没关系,但我正在绞尽脑汁想了解这个选择背后的原因。

考虑以下示例:

template<typename T>
struct S { S(T) {} };

S f() { return 0; }

int main() {
    auto s = f();
    (void)s;
}

编译失败,错误如下:

error: use of class template 'S' requires template arguments; argument deduction not allowed in function return type

很容易修复,这不是问题,像这样的东西很好用:

auto f() { return S{0}; }

但是,我想了解在函数 return 类型中也允许 class 模板参数推导的缺点是什么。
乍一看,它看起来像是一个愚蠢的限制,但我很确定我在这里遗漏了一些重要的东西。

这里没有任何语言法律问题:如果您指定 return 类型(而不是 autoT,其中 T 是模板类型),那么 return 类型必须有效。让我给你一个更简单、更好的例子:

std::vector function() {
    return std::vector<int>();
}

显然它无法编译,即使没有花哨的模板,auto 和类型推导,因为 std::vector 不是类型,std::vector<int> 是。

当您将 S 指定为 return 类型时,您基本上

  • 防止编译器推导类型本身
  • 指定无效的 return 类型,因为 S 不是类型,S<int> 是。

只是我手挥的两分钱总结了我的理解:

S f() { return 0; }

S 不是可以推导的类型,它只是一个模板。你可以写

template<typename T>
S<T> f() { return 0;}

但现在很明显,为了一个电话

auto s = f();

无法推断 T 应该是什么类型。

Why isn't argument deduction allowed in function return type?

因为标准是这么说的。

您可能会问这个问题:为什么这些代码行之间存在差异:

S s = 0;            // OK
S s() { return 0; } // error - even though this is also copy-initializing an "S" from 0

你可以想出一个简单的解释为什么第一个应该没问题,为什么第二个不应该 - 但从根本上说 class 模板参数推导被提议只解决第一种情况而不是第二。第一个没问题,因为标准是这么说的,第二个是错误的,因为标准是这么说的。

有一个扩展提议(P1021,在 "Return type deduction for functions" 下)将解决第二种情况。不管你认为这是个好主意...¯\_(ツ)_/¯