Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 是';typename';当模板参数包含非静态成员的名称时为必填项?_C++_Templates_Language Lawyer_Typename - Fatal编程技术网

C++ 是';typename';当模板参数包含非静态成员的名称时为必填项?

C++ 是';typename';当模板参数包含非静态成员的名称时为必填项?,c++,templates,language-lawyer,typename,C++,Templates,Language Lawyer,Typename,另一个是给语言律师的 对于以下代码,无论是否存在A的显式实例化: clang 3.0要求在声明Type1和Type3时使用typename,但不要求声明Type2 gcc 4.8.1要求在声明Type1时使用typename,但不使用Type2或Type3 struct C { int f1(); static int f2(); int m; }; template<int i> struct S { typedef int Type; }; t

另一个是给语言律师的

对于以下代码,无论是否存在
A
的显式实例化:

clang 3.0要求在声明
Type1
Type3
时使用
typename
,但不要求声明
Type2

gcc 4.8.1要求在声明
Type1
时使用
typename
,但不使用
Type2
Type3

struct C
{
    int f1();
    static int f2();
    int m;
};

template<int i>
struct S
{
    typedef int Type;
};

template<typename T>
struct B : C
{
};

template<typename T>
struct A : B<T>
{
    void f()
    {
        typedef typename S<sizeof(C::f1())>::Type Type1; // typename required
        typedef S<sizeof(C::f2())>::Type Type2; // typename not required
        typedef typename S<sizeof(C::m)>::Type Type3; // typename not required?
    }
};

template struct A<int>;
struct C
{
int f1();
静态int f2();
int m;
};
模板
结构
{
typedef int类型;
};
模板
结构B:C
{
};
模板
结构A:B
{
void f()
{
typedef typename S::Type Type1;//需要typename
typedef S::Type2;//不需要typename
typedef typename S::Type Type3;//是否不需要typename?
}
};
模板结构A;
I图
Type1
的声明中需要
typename
,因为调用非静态成员的隐含对象参数是
(*this)
,其类型是依赖的。 请参见[over.call.func]:

在非限定函数调用中,名称不是由
->
运算符限定的,它具有更一般的主表达式形式。按照函数调用中名称查找的常规规则,在函数调用的上下文中查找名称。通过该查找找到的函数声明构成候选函数集。由于名称查找的规则,候选函数集由(1)全部非成员函数或(2)部分T类的成员函数组成。在情况(1)中,参数列表与调用中的表达式列表相同。在案例(2)中,参数列表是调用中的表达式列表,通过添加隐含的对象参数(如在限定函数调用中)来增加。如果关键字
this
在范围内,并且引用类
T
,或派生类
T
,则隐含的对象参数为
(*此)

按照此逻辑,
Type2
的声明中不需要
typename
,因为该成员是静态的。在
Type3
的声明中也不需要
typename
,因为表达式不是对非静态成员的调用

我通读了以下内容: .. 并通过[temp.dep.type]和[temp.dep.expr]中的规则。我看不到任何东西指定在确定表达式是否依赖时,是否应该对非静态成员函数名进行特殊处理。标准是否规定了这一点


编辑:删除了关于基于[class.mfct.non-static]转换为类成员访问表达式的讨论——Casey的回答对此进行了更详细的讨论

我不完全确定,但这里有一个使用您的报价的解释:

  • C::f2
    只是一个普通函数,因此它是无条件已知的,并且
    sizeof(C::f2())
    不依赖于模板参数
    T
    ——它只是一个普通类型,就像
    s

  • C::f1()
    实际上是
    this->f1()
    ,由于
    this
    依赖于模板参数
    T
    Sf1())>
    是一个依赖类型,因此需要消除歧义


C
是通过非限定名称查找在阶段1查找期间解析的非依赖名称
C::f1
C::f2
也是在模板查找的第一阶段通过限定名称查找解析的非依赖名称。无论
C
是否是
a
的基础,这都是正确的

问题中引用的[class.mfct.non-static]文本似乎来自C++03。C++11文本(9.3.1/3)内容如下:

如果名称查找(3.4),则在类
X
的成员中使用不属于类成员访问语法(5.2.5)一部分且不用于形成成员指针(5.3.1)的id表达式(5.1)时,可以使用
(5.1.1)将id表达式中的名称解析为某个类的非静态非类型成员
C
,如果id表达式是潜在计算的[emph.mine]或
C
X
X的基类,则id表达式将转换为类成员访问表达式(5.2.5)使用
(*this)
(9.3.2)作为
操作符左侧的后缀表达式

C::f1
可能在可以使用
this
的上下文中进行评估,因此
C::f1
被转换为
(*this).C::f1
。由于
B
明确依赖于模板参数,
(*this).C::f1
是14.6.2.1/5中未知专门化的成员。[本标准使用术语“未知专业化的成员”来表示可能表示模板某些专业化成员但并非所有专业化成员的表达式。]

由于
(*this).C::f1
表示未知专门化的成员,因此根据14.6.2.2/5,它是一个类型相关的类成员访问表达式。根据14.6.2.2/1,扩展而言,
(*this).C::f1()
依赖于类型<根据14.6.2.3/2,code>sizeof((*this).C::f1())
取决于值
S
-一个带有值相关参数表达式的简单模板id-然后根据14.6.2.1/8成为相关类型

由于
S
是依赖的

S::Type

根据14.6.2/1“如果id表达式的非限定id是一个模板id,其中任何模板参数都依赖于模板参数”。最后,但并非最不重要的是,14.6/2要求使用关键字
typename
来指示依赖名指代类型:

typename S::Type

我想这就是全部的原因