L值引用抽象类和`decltype`

时间:2014-08-02 17:19:40

标签: c++ c++11 abstract-class decltype

我想出了以下一段代码,认为它不起作用,但令我惊讶的是它的工作非常好,我想要一些解释。

#include <cstdio>
#include <algorithm>

struct Abstract
{
    Abstract()
        { printf("\tConstructing Abstract instance.\n"); }

    virtual const char* name() const =0;
    auto talk() const -> decltype(*this)
    {
        printf("My name is %s.\n",name());
        return *this;
    }
};

struct Concrete
    : public Abstract
{
    Concrete() 
        { printf("\tConstructing Concrete instance.\n"); }
    const char* name() const
        { return "Bond"; }
};

int main()
{
    Concrete C;
    printf("James %s.\n",C.talk().name());
}

此代码的输出为:

    Constructing Abstract instance.
    Constructing Concrete instance.
My name is Bond.
James Bond.

Q1 (这与C ++ 11无关,只需删除decltype并将auto替换为const Abstract&)。为什么编译器接受语法C.talk().name()

除非我弄错了,我认为表达式C.talk()可以是prvalue(Abstract的副本,不是因为只有一个构造函数输出)或者左值引用,在这种情况下我不确定因为对于抽象类的左值引用对我来说似乎也是不可能的。

Q2 这引出了第二个问题:decltype如何“知道”返回某种引用,而不是一个简单的值?

1 个答案:

答案 0 :(得分:8)

Q1:不仅允许对抽象类进行左值引用,而且实际上多态性必不可少。请注意,引用类型对应于表达式的 static 类型,而不是对象的 dynamic 类型,当然这不能是抽象类(嗯,实际上是也不完全正确,但它足够接近这个答案的目的)。

因此语法C.talk().name()被接受,因为类型Abstract包含成员函数name()的声明,并且它将被正确执行,因为在执行时,实际调用的函数取决于在动态类型上,即Concrete,其实现为name()

Q2: *this是左值表达式,左值表达式的decltype给出左值引用。