C ++ 98标准在何处指定对静态成员的调用何时依赖于模板?

时间:2013-06-02 21:43:17

标签: c++ templates language-lawyer c++98

使用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,命名一个用依赖类型声明的对象。

3 个答案:

答案 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)

fS的成员,这是一个模板,因此在f中使用S取决于S的模板参数

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

  

如果符合以下情况,则id-expression依赖于值:

     

...

     

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

这适用于此处的'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似乎有一个错误。