0

这里阅读,这个 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) 在这个问题中,一个人问为什么他的代码没有编译,答案是成员函数 makeObject 缺少“const”说明符。我得到了答案,但不知道为什么需要 const。

什么给了以下声明

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

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

4

3 回答 3

3

一般来说,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 有效的规则。

于 2013-04-06T16:06:19.450 回答
2
  1. 不。 decltype创建一个未评估的上下文,就像sizeof. 编译器只查看类型信息,仅查看其他信息。

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

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

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

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

答案:

1) 不。decltype只在编译时计算表达式的类型,而不在运行时计算表达式。出于这个原因,decltype据说是一个“未评估的上下文”,因为它是sizeof并且noexcept

2) 请注意,在此声明中

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

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

3)问题不在于声明

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

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

auto val = builder.makeObject();

因为builderconst Builder&唯一const可以调用的方法,builder并且最初makeObject()不是其中之一。然后用这个方法const解决了这个问题。

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

于 2013-04-06T16:14:07.383 回答