【问题标题】:C++11 - Clearing out Return Value Syntax and decltype KeywordC++11 - 清除返回值语法和 decltype 关键字
【发布时间】:2013-04-06 15:57:30
【问题描述】:

here 阅读,这段 C++11 代码对我来说似乎很奇怪:

template <typename Builder>
auto
makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )
{
    auto val = builder.makeObject();
    // do stuff with val
    return val;
}

我有几个问题:

1) 在执行实际调用之前,decltype(builder.makeObject()) 是否会再调用一次 makeObject 函数?

2) 如果不是并且在编译时一切都已知(所以它是一种增强宏),为什么以下语法无效,我需要新的返回值语法?

//WRONG    
template <typename Builder>
    decltype( builder.makeObject() )
    makeAndProcessObject (const Builder& builder)
    {
        auto val = builder.makeObject();
        // do stuff with val
        return val;
    }

[奖励问题 - 奖励 +1 答案] 3) 在this 问题中,一个人问为什么他的代码没有编译,答案是成员函数makeObject 缺少“const”说明符。我得到了答案,但不知道为什么需要 const。

以下声明的含义

template <typename Builder>
auto
makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )

如果 const Builder& 对象引用具有 const makeObject 或非 const makeObject? decltype(builder.makeObject()) 部分必须只找出函数的返回类型是什么,它不应该关心函数是否修改了作为参数传递的对象!

【问题讨论】:

  • 每个问题一个问题。停止尝试抵消 SO 的机制(“奖励问题 - 奖励 +1 答案”wtf)

标签: c++ c++11


【解决方案1】:

一般来说,C++ 中的东西在被声明之前是不可用的。在您的示例中,您尝试在声明之前使用 builder:

template <typename Builder>
    decltype( builder.makeObject() ) // using builder here
    makeAndProcessObject (const Builder& builder) // but builder isn't declared until here
    {
        auto val = builder.makeObject();
        // do stuff with val
        return val;
    }

添加了函数返回类型的新语法来解决这个问题。

template <typename Builder>
auto // dummy return type, meaning we will give it later
makeAndProcessObject (const Builder& builder)  // declaring builder here
-> decltype( builder.makeObject() ) // using builder here -- no problem.
{
    auto val = builder.makeObject();
    // do stuff with val
    return val;
}

至于你的额外问题:语言更简单地说你必须给 decltype 一个有效的表达式,而不是有另一组关于哪些参数对 decltype 有效的规则。

【讨论】:

    【解决方案2】:
    1. 没有。 decltypesizeof 一样创建一个未评估的上下文。编译器只查看类型信息。

    2. 您不能在前导返回类型中使用参数。

      decltype( builder.makeObject() ) makeAndProcessObject (const Builder& builder)
      

    导致错误,因为builder 是未知标识符。这就是创建尾随返回类型的原因。

    • 在未评估的上下文中,类型信息很重要。而this 参数是否为const 是类型信息的一部分。如果decltype 没有进行重载解析,那将毫无用处。如果您从未见过基于成员函数的 const-ness 的重载,这可能没有意义,但可以有两个具有相同名称和参数的函数,其中一个调用 const 视图对象和一个非const。并且返回类型可以不同(实际上,它们通常相差 const)。

    【讨论】:

      【解决方案3】:

      答案:

      1) 否。decltype 仅在编译时计算表达式的类型,而不在运行时计算表达式。因此,decltype 被称为“未评估的上下文”,因为它是 sizeofnoexcept

      2) 请注意,在此声明中

      template <typename Builder>
      decltype( builder.makeObject() )
      makeAndProcessObject (const Builder& builder)
      

      编译器在看到它的声明const Builder&amp; builder 之前看到builder 而对于接受的声明,在确定返回类型的那一刻,编译器已经解析了它需要的所有信息。 auto 关键字告诉编译器坚持返回类型将在稍后提供更多信息时给出。

      3) 问题不在于声明

      template <typename Builder>
      auto
      makeAndProcessObject (const Builder& builder) -> decltype( builder.makeObject() )
      

      实际上是函数体。更准确地说,是以下行:

      auto val = builder.makeObject();
      

      由于builderconst Builder&amp;,因此只能在builder 上调用const 方法,并且最初makeObject() 不是其中之一。然后用const这个方法解决了这个问题。

      更新:在阅读了 Ben Voigtanswer 之后。与我上面所说的相反,这个问题出现在声明中,因为它使用了decltype(builder.makeObject()),并且我用于函数体的相同参数也适用于此。

      【讨论】:

      • 另一个写得很好的答案 +1!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-02
      • 1970-01-01
      相关资源
      最近更新 更多