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,并在以后解决模糊性.标准是否可以帮助实现者这样做?
问题是你引用的段落最终应用太晚了.在到达那里之前,编译器必须确定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名称是否为模板,并且可以决定以下<是否大于,或者打开模板参数列表.当然,一旦它解析了下面的标记,它就不能在以后"重新绑定"该参数,因为在一般情况下,重新绑定可能会改变其含义
<,使解析失效.实际上,尽管标准没有尽可能明确地说明,但在这种情况下,名称查找必须是非限定名称查找(或类成员访问,如果名称前面有一个.或一个->运算符).
| 归档时间: |
|
| 查看次数: |
1013 次 |
| 最近记录: |