4

使用 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;

取消注释 'f' 的重载会导致 Clang 报告错误“在依赖类型名称之前缺少 'typename'”。G++ 4.8 报告有或没有重载的相同错误。无论有没有过载,msvc10 都不会给出任何错误。

标准在哪里说明“f”是否依赖以及是否需要“typename”?如果不需要'typename',标准在哪里说明在这种情况下是否应该执行重载解析?

编辑:

澄清一下:我提到重载解析的原因是可能需要执行重载解析来确定常量表达式“sizeof(f(0))”的值。如果(我假设)在确定表达式是否依赖于类型时不执行重载决议,那么常量表达式“sizeof(f(0))”的值是不可能确定的(在解析时)何时依赖重载'f' 存在:例如

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 表达式,它命名一个用依赖类型声明的对象,那么标准认为它是依赖于类型的。

4

3 回答 3

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:

除非下面描述,如果任何子表达式是类型相关的,则表达式是类型相关的。

而且我在异常列表中看不到依赖类型的子表达式或任何相关的内容。

于 2013-06-02T23:08:25.987 回答
2

涵盖此场景的 C++98 标准段落可在 [temp.dep.expr] 中找到

如果 id 表达式包含以下内容,则它是类型相关的:

  • 使用依赖类型声明的标识符,

正如 DR 541 中所报告的那样,这种措辞对于过载并可能声明为一种以上类型的标识符有些模糊:http ://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html

通过将段落更改为:

如果 id 表达式包含以下内容,则它是类型相关的:

  • 一个标识符,通过名称查找与使用依赖类型声明的一个或多个声明相关联,

考虑以下代码时:

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)是依赖的。

在确定函数调用表达式是否依赖时 - 尽管不执行重载决议 - 会考虑函数的所有重载。

于 2013-06-03T13:44:21.557 回答
0

f是 的成员S,它是一个模板,因此对fwithin的任何使用S都依赖于 的模板参数S

14.6.2.3 [temp.dep.constexpr] 第 2 段:

如果满足以下条件,则 id 表达式是值相关的:

...

— 它命名一个静态成员函数,它是当前实例化的依赖成员

这适用于此处的“f”,它是当前实例化的从属成员。14.6.2.1 [temp.dep.types] 第 4 段:

...

如果名称是当前实例化的成员,当查找时,该名称是当前实例化类的至少一个成员,则该名称是当前实例化的从属成员。

因此sizeof(f(0))是依赖的,I<sizeof(f(0))>是依赖的,并且I<sizeof(f(0))>::Type需要typename将其标识为类型而不是数据成员。

因此,gcc 有权投诉。

MSVC 使用模板进行后期查找,因此不会抱怨。这是一个错误,但我认为他们从未打算修复它。

Clang 似乎在这里有一个错误。

于 2013-06-04T10:47:47.987 回答