c++ - 当模板参数包含非静态成员名称时,是否需要 'typename'?

标签 c++ templates language-lawyer typename

另一份给语言律师的。

对于下面的代码,无论A<int>是否显式实例化存在:

clang 3.0 需要 typenameType1的声明中和Type3 ,但不是Type2 .

gcc 4.8.1 需要 typenameType1的声明中,但不是Type2Type3 .

struct C
{
    int f1();
    static int f2();
    int m;
};

template<int i>
struct S
{
    typedef int Type;
};

template<typename T>
struct B : C
{
};

template<typename T>
struct A : B<T>
{
    void f()
    {
        typedef typename S<sizeof(C::f1())>::Type Type1; // typename required
        typedef S<sizeof(C::f2())>::Type Type2; // typename not required
        typedef typename S<sizeof(C::m)>::Type Type3; // typename not required?
    }
};

template struct A<int>;

我算typename声明中需要Type1因为调用非静态成员的隐含对象参数是 (*this) ,其类型是相关的。 请参阅[over.call.func]:

In unqualified function calls, the name is not qualified by an -> or . operator and has the more general form of a primary-expression. The name is looked up in the context of the function call following the normal rules for name lookup in function calls. The function declarations found by that lookup constitute the set of candidate functions. Because of the rules for name lookup, the set of candidate functions consists (1) entirely of non-member functions or (2) entirely of member functions of some class T. In case (1), the argument list is the same as the expression-list in the call. In case (2), the argument list is the expression-list in the call augmented by the addition of an implied object argument as in a qualified function call. If the keyword this is in scope and refers to class T, or a derived class of T, then the implied object argument is (*this).

按照这个逻辑,typename Type2的声明中不需要因为成员是静态的。也不是typename Type3声明中需要因为表达式不是对非静态成员的调用。

我已阅读此内容:Where and why do I have to put the "template" and "typename" keywords? ..并通过 [temp.dep.type] 和 [temp.dep.expr] 中的规则。我看不到任何指定在确定表达式是否依赖时是否应对非静态成员函数名称进行特殊处理的内容。标准有规定吗?

编辑:删除了基于 [class.mfct.non-static] 转换为类成员访问表达式的讨论 - Casey 的答案更详细地讨论了这一点。

最佳答案

C是在第一阶段查找过程中通过非限定名称查找解析的非依赖名称。 C::f1C::f2是在模板查找的第一阶段中通过限定名称查找解析的非依赖名称。无论 C 是否都是如此是 A 的基数.

问题中引用的[class.mfct.non-static]文本似乎来自C++03。 C++11 文本 (9.3.1/3) 内容如下:

When an id-expression (5.1) that is not part of a class member access syntax (5.2.5) and not used to form a pointer to member (5.3.1) is used in a member of class X in a context where this can be used (5.1.1), if name lookup (3.4) resolves the name in the id-expression to a non-static non-type member of some class C, and if either the id-expression is potentially evaluated [emph. mine] or C is X or a base class of X, the id-expression is transformed into a class member access expression (5.2.5) using (*this) (9.3.2) as the postfix-expression to the left of the . operator.

C::f1 可能在 this 的上下文中进行评估可以使用,所以C::f1转换为(*this).C::f1 。自 B<T>显式依赖于模板参数 (*this).C::f1未知专业的成员(根据 14.6.2.1/5)。 [标准使用术语“未知特化的成员”来指示表达式可以指示模板的某些特化的成员,但不能证明对于所有 特化。 ]

(*this).C::f1表示未知特化的成员,它是每个 14.6.2.2/5 的类型相关类成员访问表达式。推而广之,(*this).C::f1()根据 14.6.2.2/1 取决于类型。 sizeof((*this).C::f1())然后根据 14.6.2.3/2值相关S<sizeof((*this).C::f1())> - 带有依赖于值的参数表达式的 simple-template-id - 是符合 14.6.2.1/8 的依赖类型。

S<sizeof((*this).C::f1())>是依赖的,

S<sizeof((*this).C::f1())>::Type

依赖于 14.6.2/1“...如果 id-expressionunqualified-idtemplate-id> 其中任何模板参数都依赖于模板参数。”最后但并非最不重要的一点是,14.6/2 需要关键字 typename用于指示依赖名称引用类型:

typename S<sizeof((*this).C::f1())>::Type

认为这就是完整的推理链。

编辑:这个答案似乎是错误的。短语“潜在评估”在 3.2/2 单一定义规则 [basic.def.odr] 中定义:

An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof.

C::f1示例中肯定是 C::f1() 的子表达式这是 sizeof 的未评估操作数根据 5.3.3/1 Sizeof [expr.sizeof]。

编辑:我相信表达式 qualified-id()当前不是,但在以下情况下应被视为类型相关:(1) 它出现在类模板的成员函数内,并且 (2) qualified-id 是表示重载集的非相关名称某个类的非静态成员函数和 (3) this 的类型是依赖的。确定表达式的类型需要按照 13.3.1.1.1/3 进行重载解析,这在 this 时是不可能的位于范围内,但未确定 this 所属类的类型指的是。

我认为这可以通过向 14.6.2.1/5 [temp.dep.type] 添加一个项目符号来实现,内容如下:

  • A qualified-id used in an unqualified function call (13.3.1.1.1/3 [over.call.func]) that denotes a set of member functions of some class T that is not the current instantiation or a non-dependent base class, when the current instantiation has at least one dependent base class.

关于c++ - 当模板参数包含非静态成员名称时,是否需要 'typename'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17642624/

相关文章:

c++ - 在 ifstream 上的 getlines [耗尽文件] 之后 seekg 的问题

c++ - 为什么 C 编译器会丢弃我的 &0xFF 掩码?

c++ - 删除对模板函数的永不运行调用,在运行时获取分配错误

c++ - 将一个函数模板的模板参数映射到另一个函数模板的模板参数 (c++)

c++ - 限制函数指针的转换

c++ - 您可以在同一对象中拥有对成员 std::shared_ptr<variable> 的成员引用吗?

c++ - 比较指向不同数组的指针是否相等是未指定的行为吗?

templates - 如何使用 .NET CLI 自定义模板获取项目名称的驼峰式版本

c++ - 如何理解C++17标准引用中的[intro.object]/3?

c++ - 在查找::之前的名称时,函数模板的名称是否应该可见?