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
}
但是,它们都接受以下代码:
struct ambiguous
{
static const int value = 0;
};
namespace N
{
void ambiguous();
int i = ambiguous::value;
}
该标准规定,名称前面的名称查找::
“仅考虑名称空间、类型和特化为类型的模板”。clang 和 gcc 拒绝此代码是否正确?如果是这样,我错过了什么?
来自 C++ 工作草案标准 n3337
3.4.3 限定名称查找 [basic.lookup.qual]
类或命名空间成员或枚举器的名称可以在应用于表示其类、命名空间或枚举的嵌套名称说明符的 :: 范围解析运算符 (5.1) 之后引用。如果嵌套名称说明符中的 :: 范围解析运算符前面没有 decltype 说明符,则查找 :: 之前的名称仅考虑其特化为 types 的名称空间、类型和模板。如果找到的名称没有指定命名空间或类、枚举或依赖类型,则程序是非良构的。
14.2 模板特化的名称 [temp.names]
对于模板参数显式限定的模板名称,必须知道该名称以引用模板。
在名称查找 (3.4) 发现名称是模板名称或 operator-function-id 或literal-operator-id 引用一组重载函数后,其中任何成员都是函数模板,如果后面跟着a
<
, the<
总是作为模板参数列表的分隔符,从不作为小于运算符。
编辑
为避免将此问题与表达式和声明之间的歧义混淆,这里是原始代码,其中模板使用类型参数而不是非类型参数。
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
}
这在所有情况下都会导致相同的错误。<
不能解释为运算符。
ambiguous
明确地是模板名称,但可以是类型或函数。可以在不知道它是否命名函数或类型的情况下解析整个模板 ID,并在稍后解决歧义。标准是否允许实施者这样做?