c++ - 为什么只有在符合 "this"条件时,数据成员的模板函数才是从属名称?

标签 c++ templates c++11 dependent-name

struct Bar {
    template<typename>
    void baz() {
    }
};

template<typename>
struct Foo {
    Bar bar;

    Foo() {
        bar.baz<int>();
    }
};

int main() {
    return 0;
}

这段代码编译得很好(在 GCC 4.7 中),但是如果我在调用前加上 bar.baz<int>()this-> , baz成为需要用 template 消除歧义的从属名称.

bar.baz<int>(); // OK
this->bar.baz<int>(); // error
this->bar.template baz<int>(); // OK

当然this->bar只能引用Bar bar , 其成员 baz显然是一个模板?为什么要添加this->让这个代码对编译器产生歧义?

附言原来,bar是需要用 this-> 消除歧义的基类模板的数据成员,但为了这个问题,我已经简化了这个例子。

最佳答案

this->bar.baz<int>(); // error

上述声明,在 template<typename T> Foo<T>::Foo() 的定义中, 格式正确,如果启用了 C++11 模式或 C++1y 模式,则应被接受。但根据 C++03,它在技术上是错误的。

两个标准都同意 this是一个依赖于类型的表达式:

C++03 14.6.2.1/1; N3690 14.6.2.1/8:

A type is dependent if it is

  • a template parameter,

  • ...

  • a [simple-]template-id in which either the template name is a template parameter or any of the template arguments is a dependent type or an expression that is type-dependent or value-dependent,

[ T是依赖类型,Foo<T> 也是.]

C++03/N3690 14.6.2.2/2:

this is type-dependent if the class type of the enclosing member function is dependent.

[自 Foo<T>是依赖类型,表达式 this在其成员定义中是依赖于类型的。]

这两个标准都从 14.6.2.2 开始:

Except as described below, an expression is type-dependent if any subexpression is type-dependent.

C++03 只有三种简单的表达方式,描述更准确:

  • 主要表达式(this 和查找名称)

  • 指定自己类型的表达式(如强制转换和新表达式)

  • 具有常量类型的表达式(如文字和 sizeof )。

第一类在C++03 14.6.2.2/3中定义:

An id-expression is type-dependent if it contains:

  • an identifier that was declared with a dependent type,

  • a template-id that is dependent,

  • a conversion-function-id that specifies a dependent type,

  • a nested-name-specifier that contains a class-name that names a dependent type.

所以孤独的表达bar不依赖:它是一个标识符和一个id-expression,但以上都不适用。

但是this->bar不是id-expression,或者在任何其他C++03 异常中,所以我们必须遵循子表达式规则。由于子表达式 this是类型相关的,包含表达式 this->bar也是依赖于类型的。

但事实上,正如您所注意到的,this->bar 的类型可以在解析模板定义时知道,而无需实例化任何模板参数。它被声明为主模板的成员,因此名称必须绑定(bind)到该成员声明。模板特化可能会使 Foo<T>::bar未声明或以不同的方式声明,但在这种情况下,根本不会使用主模板,而当前定义的 Foo()对于该特化,将被忽略。这就是为什么 C++11 定义了“当前实例化”的概念并将其用于类型相关表达式的传染性的进一步异常(exception)。

N3690 14.6.2.1/1:

A name refers to the current instantiation if it is

  • in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name of the class template or nested class

  • in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in <> (or an equivalent template alias specialization),

  • ...

[第一个项目符号是 Foo是当前的实例化。第二个说Foo<T>是当前的实例化。在本例中,两者命名相同的类型。]

14.6.2.1/4:

A name is a member of the current instantiation if it is

  • An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.

  • A qualified-id in which ...

  • An id-expression denoting the member in a class member access expression for which the type of the object expression is the current instantiation, and the id-expression, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof.

[第一个项目符号是 bar单独是当前实例化的成员。第三个子弹说this->bar是当前实例化的成员。]

最后,C++11 为类型相关表达式添加了第四类规则,用于成员访问。 14.6.2.2/5:

A class member access expression is type-dependent if the expression refers to a member of the current instantiation and the type of the referenced member is dependent, or the class member access expression refers to a member of an unknown specialization.

this->bar确实引用了当前实例化的成员,但类型为 Bar被引用的成员不依赖。所以现在this->bar不依赖于类型,名称 bazthis->bar.baz在模板定义期间作为非依赖名称查找。 template baz 之前不需要关键字.

关于c++ - 为什么只有在符合 "this"条件时,数据成员的模板函数才是从属名称?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24588207/

相关文章:

c++ - 消除 "conversion to std::vector<int>::size_type to int"警告

c++ - 超出芯片组允许的最大数据类型。 C++

c++ - 错误 : expected unqualified-id before ‘<’ token

c++ - shared_ptr 原子函数采用指针而不是引用的基本原理

c++ - 如何在没有 std::function 和 auto 的情况下定义 lambda 表达式?

c++ - TBB书中的代码

c++ - QUdpSocket 高速率消息读取

c++ - 奇怪的模板错误 : error C2783: could not deduce template argument

C++ 概念看到我的类型的函数,但看不到 std::vector 的函数

c++ - 类模板的别名