在查找:::之前的名称时,是否应该可以看到函数模板的名称?

wil*_*llj 8 c++ templates language-lawyer

clang和gcc都拒绝这个代码:

template<int i>
struct ambiguous
{
    static const int value = i;
};

namespace N
{
    template<int i>
    void ambiguous();

    int i = ambiguous<3>::value; // finds the function template name
}
Run Code Online (Sandbox Code Playgroud)

但是,他们都接受以下代码:

struct ambiguous
{
    static const int value = 0;
};

namespace N
{
    void ambiguous();

    int i = ambiguous::value;
}
Run Code Online (Sandbox Code Playgroud)

该标准表示名称查找前面的名称::"仅考虑其专业化类型的名称空间,类型和模板".clang和gcc是否正确拒绝此代码?如果是这样,我错过了什么?

来自C++工作草案标准n3337

3.4.3限定名称查找[basic.lookup.qual]

在将:: scope resolution运算符(5.1)应用于表示其类,名称空间或枚举的嵌套名称说明符之后,可以引用类或名称空间成员或枚举器的名称.如果嵌套名称说明符中的:: scope resolution运算符前面没有decltype-specifier,则查找此前面的名称::仅考虑其专门化为类型的名称空间,类型和模板.如果找到的名称未指定名称空间或类,枚举或依赖类型,则程序格式错误.

14.2模板特化名称[temp.names]

对于要由模板参数显式限定的模板名称,必须知道名称才能引用模板.

名称查找(3.4)后发现名称是模板名称或者operator-function-id或literal-operator-id引用一组重载函数,如果后面跟着<<函数模板,其中任何成员都是函数模板a ,始终作为template-argument-list的分隔符,而不是less-than运算符.

编辑

为了避免将此问题与表达式和声明之间的歧义混淆,这里是使用类型参数而不是非类型参数的模板的原始代码.

template<class>
struct ambiguous
{
    static const int value = 0;
};

namespace N
{
    template<class>
    void ambiguous();

    int i = ambiguous<int>::value; // finds the function template name
}
Run Code Online (Sandbox Code Playgroud)

这在所有情况下都会导致相同的错误.将<不能被解释为一个运营商.

ambiguous明确地是模板名称,但可以是类型或函数.可以在不知道它是否命名函数或类型的情况下解析整个模板ID,并在以后解决模糊性.标准是否可以帮助实现者这样做?

Jam*_*nze 8

问题是你引用的段落最终应用太晚了.在到达那里之前,编译器必须确定in ambiguous<3>::value,<>是模板参数分隔符,并且不大于和小于.(考虑:

int ambiguous;
int value:
//  ...
int i = ambiguous<3>::value;
Run Code Online (Sandbox Code Playgroud)

,其解析为(ambiguous < 3) > ::value,其中,<>分别是小于和大于,.)这涉及的查找ambiguous作为不合格的名称,并结合该符号N::ambiguous.之后,你被困N::ambiguous<3>在左边 的实例化模板::,这是不合法的.

编辑:

这个问题并不像人们所希望的那样清晰:标准仅涉及第14.2节中的3.4节,其中讨论了这一点,3.4节讨论了所有可能的名称查找规则.另一方面,实际上只有一种方法可以解释它:编译器无法进一步解析任何内容,直到它知道ambiguous名称是否为模板,并且可以决定以下<是否大于,或者打开模板参数列表.当然,一旦它解析了下面的标记,它就不能在以后"重新绑定"该参数,因为在一般情况下,重新绑定可能会改变其含义 <,使解析失效.实际上,尽管标准没有尽可能明确地说明,但在这种情况下,名称查找必须是非限定名称查找(或类成员访问,如果名称前面有一个.或一个->运算符).