使用Clang 3.0 -std = c ++ 98进行编译,接受以下代码:
template<int>
struct I
{
typedef int Type;
};
template<class>
struct S
{
static int f(int);
//static int f(int*);
// implicitly instantiates I<sizeof(int)>
typedef I<sizeof(f(0))>::Type Type;
};
S<int>::Type s;
取消注释&#39; f&#39;导致Clang报告错误&#34;缺少&#39; typename&#39;在依赖类型名称之前#34;。无论有没有过载,G ++ 4.8报告相同的错误。 msvc10在出现或不出现过载时都不会出现任何错误。
标准在哪里说是否&#39; f&#39;是依赖和&#39; typename&#39;是必须的?如果&#39; typename&#39;不是必需的,标准在哪里说明在这种情况下是否应该执行重载决策?
编辑:
澄清:我提到重载解析的原因是可能需要执行重载决策以确定常量表达式(f(0))&#39;的值。如果(我假设)在确定表达式是否依赖于类型时不执行重载决策,则常量表达式的值(f(0))&#39;是不可能确定(在解析时)依赖过载的时间是什么?存在:例如
template<int>
struct I
{
typedef int Type;
};
template<class T>
struct S
{
static T f(int);
typedef typename I<sizeof(f(0))>::Type Type;
};
S<int>::Type t;
使用Clang 3.0 -std = c ++ 98进行编译,这不会产生任何错误。这似乎对我来说是正确的,因为标准认为表达式是依赖于类型的,如果它是一个id-expression,命名一个用依赖类型声明的对象。
答案 0 :(得分:2)
从属名称在14.6.2中定义。 gcc抱怨I<sizeof(f(0))>
依赖,让我们想一想。
14.6.2.1最后一颗子弹:
模板ID,其中模板名称是模板参数 或任何模板参数是依赖类型或表达式 这是依赖于类型的还是依赖于价值的
所以sizeof(f(0))
必须依赖于价值。 14.6.2.3p2:
如果使用一元表达式,则以下形式的表达式取决于值 是类型依赖的...... sizeof unary-expression
所以我们依赖于f(0)被认为是依赖的。 (很少有实验表明,gcc会将成员的任何依赖函数和自由函数视为不依赖。)14.6.2.2:
除非如下所述,否则如果任何子表达式依赖于类型,则表达式依赖于类型。
我没有看到任何类型相关的子表达式或异常列表中的任何相关内容。
答案 1 :(得分:2)
涵盖此场景的C ++ 98标准段落位于[temp.dep.expr]
如果id-expression包含:
,则它依赖于类型
- 使用依赖类型
声明的标识符
对于重载且可能使用多种类型声明的标识符,此措辞有些模糊,如DR 541中所述:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html
通过将段落更改为:
,解决了这个问题(在最近的草案中)如果id-expression包含:
,则它依赖于类型
- 通过名称查找关联的标识符与使用从属类型声明的一个或多个声明
考虑以下代码时:
template<class T>
struct S
{
static int f(int);
static int f(int*);
static T g(int*);
static int g(int);
static const int x = sizeof(f(0));
static const int y = sizeof(g(0));
};
我的解释是表达式f
中的标识符f(0)
不依赖,而表达式g
中的标识符g(0)
是依赖的。
在确定函数调用表达式是否依赖时 - 尽管不执行重载解析 - 会考虑函数的所有重载。
答案 2 :(得分:0)
f
是S
的成员,这是一个模板,因此在f
中使用S
取决于S
的模板参数
如果符合以下情况,则id-expression依赖于值:
...
- 它命名一个静态成员函数,它是当前实例化的依赖成员
这适用于此处的'f',它是当前实例化的从属成员。 14.6.2.1 [temp.dep.types]第4段:
...
如果名称是当前实例化的成员,则它是当前实例化的成员,当查找时,它指的是当前实例化的类的至少一个成员。
因此sizeof(f(0))
依赖,I<sizeof(f(0))>
依赖,I<sizeof(f(0))>::Type
需要typename
将其标识为类型而非数据成员。
MSVC使用模板进行延迟查找,因此不会抱怨。这是一个错误,但我认为他们不打算修复它。
Clang似乎有一个错误。