c++ - 为什么我们不能自动推断返回类型?

标签 c++ c++11

最近我和一个 friend 一起工作,他想让 C++ 更像 Haskell,我们想要一个基本上像这样的函数:

auto sum(auto a, auto b) {
    return a + b;
}

显然我不能使用auto作为参数类型,所以我改成这样:

template<class A, class B>
auto sum(A a, B b) {
    return a + b;
}

但这也不起作用。我们最终意识到我们需要这个:

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b) {
    return a + b;
}

所以我的问题是,有什么意义?不是decltype只是重复信息,因为编译器可以只看return语句吗?

我认为可能需要它,所以我们可以只包含一个头文件:

template<class A, class B>
auto sum(A a, B b) -> decltype(a + b);

...但无论如何我们都不能使用这样的模板。

我考虑的另一件事是编译器可能更容易,但似乎实际上会更难。

案例1:使用decltype

  • 找出decltype语句的类型
  • 找出任何返回值的类型
  • 看看他们是否匹配

案例2:没有decltype

  • 找出任何返回值的类型
  • 看看他们是否匹配

考虑到这些,decltype 的尾随返回类型有什么意义?

最佳答案

好吧 - 自从提出原始问题以来已经过去了一段时间,现在的答案是你可以!

是的,这个问题确实被标记为 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 的答案,出于历史原因保留在这里,还有一些来自 future 的评论(C++14 及更高版本):: p>

如果我们有以下情况:

template<class A, class B, class C>
auto sum(A a, B b, C c) {
   if (rand () == 0) return a + b;

   // do something else...

    return a + c;
}

.. 其中 a + ba + c 表达式产生不同类型的结果。 编译器应该决定将什么作为该函数的返回类型,为什么? 这种情况已经被 C++11 lambdas 覆盖,只要 return 语句可以推导出为相同的类型,就可以省略返回类型(需要注意标准引用,一些来源声称只有一个返回表达式是允许的,这是 gcc 故障)。


来自 future 的注释(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); // 4.5
    auto a2 = sum(1, 2, 3.5); // 3
}

回到原来的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)
{
}

来自 future 的注释(C++14 及更高版本):如果在编译器看到调用时定义不可用,您仍然不能拥有具有 auto 返回类型的声明.

关于c++ - 为什么我们不能自动推断返回类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7589809/

相关文章:

c++ - 什么可能导致此内存访问错误 (C++)?可能是未定义的行为?

c++ - 为游戏数据流量添加 SSL 加密是否值得?

使用 std::atomic 的 C++ 线程安全增量,带模而不带互斥锁

c++ - 检测/获取 lambda 函数的捕获值

c++ - 如何在等待 std::cin 时终止 C++11 线程?

c++ - 难以将函数转换为单个方程 (constexpr)

c++ - DirectX10 仅绘制一个渲染目标

C++ 多态性,关于宣布对派生类的基类引用

c++ - 你怎么能把一组数字变成大部分的整数呢?

c++ - 返回派生类类型的基类中的方法?