为什么在函数返回类型中不允许使用参数推导?

时间:2018-05-31 10:36:05

标签: c++ templates language-lawyer c++17 argument-deduction

最明显的答案可能是 - ,因为标准是这样说的。 那很好,但是我绕着它去理解这个选择背后的原因。

考虑以下示例:

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

S f() { return 0; }

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

无法编译错误,如:

  

错误:使用课程模板&#39; S&#39;需要模板参数;函数返回类型中不允许使用参数推导

很容易解决,这不是一个问题,像这样的工作正常:

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

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

3 个答案:

答案 0 :(得分:10)

这里没有语言规则:如果您指定了返回类型(而不是autoT其中T是模板类型),则该返回类型具有有效。让我给你一个更简单,更好的例子:

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

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

当您指定S作为返回类型时,基本上

  • 防止编译器推断出类型本身
  • 指定无效的退货类型,因为S不属于S<int>类型。

答案 1 :(得分:5)

  

为什么函数返回类型中不允许参数推导?

因为标准是这样说的。

你可以问一个问题:为什么这些代码行之间存在差异:

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

你可以想出一个手写的解释,为什么第一个应该没问题,为什么第二个不应该 - 但基本上,类模板参数推导被提议只解决第一个案例而不是第二个案例。第一个是好的,因为标准是这样说的,第二个是错误,因为标准是这样说的。

有一个扩展建议(P1021,在“函数的返回类型扣除”下,将解决第二种情况。你是否认为这是一个好主意...¯\ _(ツ)_ /¯

答案 2 :(得分:4)

只是我的手工波浪两分钱总结了我的理解:

S f() { return 0; }

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

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

但现在很明显,对于一个电话

auto s = f();

没有办法推断出T应该是什么类型。