[英]Template class with nested template class, g++ compiles fine, vs2013 wont compile
I'm implementing my own map and this is a piece of the code. 我正在实现自己的地图,这是一部分代码。 A part of the code that is troubling me is these two declarations: 这两个声明是困扰我的一部分代码:
template<typename KEY, typename VAL>
Map<KEY,VAL>::MapPair<KEY,VAL> Map<KEY,VAL>::make_map_pair(KEY k, VAL v){
return MapPair<KEY,VAL>(k,v);
}
template<typename KEY, typename VAL>
template<typename K, typename V>
Map<KEY,VAL>::MapPair<K,V>& Map<KEY,VAL>::MapPair<K,V>::setKey(K keyp, V val){
key = keyp;
value = val;
}
The class def is as follows: 类def如下:
template <typename KEY, typename VAL>
class Map{
private:
template<typename K, typename V>
class MapPair {
public:
K key;
V value;
MapPair(){};
MapPair(K key, V value);
MapPair<K,V>& setKey(K key, V val);
V& getValue();
K getKey();
bool operator==(MapPair<K,V> item);
};
List<MapPair<KEY,VAL>> pair_list_;
MapPair<KEY,VAL> make_empty_map_pair(KEY k);
MapPair<KEY,VAL> make_map_pair(KEY k, VAL v);
public:
Map(){}
bool exists(KEY key);
VAL& operator[](KEY key);
VAL pop_pair(KEY key);
};
This code compiles without a peep from g++, but Visual Studio 2013 flips out errors: 这段代码编译时不会出现g ++的偷窥,但Visual Studio 2013会抛出错误:
error C2059: syntax error : ')'
error C2059: syntax error : ')'
each of the top function definitions generate an error. 每个顶级函数定义都会产生一个错误。
From g++ under debain 7.5 从Debain 7.5下的g ++
g++ -Wall -c -std=c++11 vm.cpp
g++ vm.o -o vm
and it runs nicely with no run time issues and does what its supposed to do. 它运行良好,没有运行时问题,并且可以执行应做的事情。
The question is why does g++ run this fine, and vs2013 wont compile it? 问题是,为什么g ++可以很好地运行,而vs2013无法编译它? What can I do to make this code compile properly on vs2013? 如何使此代码在vs2013上正确编译? What kind of habits can I develop to ensure portability in the code that I write? 我可以养成什么样的习惯来确保所编写代码的可移植性?
So it turns out, VS2013 likes to have typename
inserted before the return type of a nested class. 事实证明,VS2013喜欢在嵌套类的返回类型之前插入typename
。 I knew I 'could' do that but id never know why I would until this instance. 我知道我可以做到这一点,但在这种情况下,身份证永远不知道为什么要这么做。
template<typename KEY, typename VAL>
typename Map<KEY,VAL>::MapPair<KEY,VAL> Map<KEY,VAL>::make_map_pair(KEY k, VAL v){
/*^^^^^ right here before the nested class object that it will return.*/
return MapPair<KEY,VAL>(k,v);
}
Best idea is to use it so the code can ported with less changes, even though g++ wont require it. 最好的主意是使用它,以便即使g ++不需要它也可以进行较少的更改来移植代码。
My reading of the C++11 standard suggests that typename
is required. 我对C ++ 11标准的阅读表明,必须输入typename
。 VS2013 is doing the right thing. VS2013做正确的事。
Without the typename
keyword, a dependent name is assumed not to name a type. 如果没有typename
关键字,则假定从属名称未命名类型。
14.6 Name resolution [temp.res] 14.6名称解析[temp.res]
2) A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename. 2)假定在模板声明或定义中使用的依赖于模板参数的名称不命名类型,除非适用的名称查找找到类型名称或该名称由关键字typename限定。
3) When a qualified-id is intended to refer to a type that is not a member of the current instantiation and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename 3)当限定ID旨在引用不是当前实例成员的类型,并且其嵌套名称说明符引用从属类型时,应在其前面加上关键字typename
7) Within the definition of a class template or within the definition of a member of a class template following the declarator-id , the keyword typename is not required when referring to the name of a previously declared member of the class template that declares a type. 7)在类模板的定义内或在declarator-id之后的类模板的成员内 ,在引用声明了类型的类模板的先前声明的成员的名称时,不需要关键字typename 。 [Note: such names can be found using unqualified name lookup, class member lookup into the current instantiation , or class member access expression lookup when the type of the object expression is the current instantiation [注意:当对象表达式的类型是当前实例时 ,可以使用非限定名称查找, 类成员查找到当前实例中或类成员访问表达式查找中找到此类名称。
14.6.2.1 Dependent types [temp.dep.type] 14.6.2.1从属类型[temp.dep.type]
A name refers to the current instantiation if it is 名称是指当前实例,如果它是
- in the definition of a primary class template or a member of a primary class template, the name of the class template followed by the template argument list of the primary template (as described below) enclosed in <> 在主类模板或主类模板的成员的定义中,类模板的名称后跟<>中包含的主模板的模板参数列表(如下所述)
When Map<KEY, VAL>
is used in the definition of Map
, it refers to the current instantiation . 当Map<KEY, VAL>
在定义用于Map
,它指的是当前实例化 。 When parsing the definition of make_map_pair
a type name qualified by Map<KEY, VAL>::
can in general be found by class member name lookup into the current instantiation . 解析make_map_pair
的定义时,通常可以通过对当前实例化的类成员名称查找来找到由Map<KEY, VAL>::
限定的类型名称。
However, when the C++ parser encounters Map<KEY, VAL>
in the return-type of a member function definition - before the declarator-id - it has not yet encountered the name of the enclosing class. 但是,当C ++解析器在成员函数定义的返回类型中(在声明者ID之前)遇到Map<KEY, VAL>
,它尚未遇到封闭类的名称。 The parser cannot determine whether or not Map
refers to the enclosing class at this point. 解析器此时无法确定Map
是否引用封闭类。
For this reason - regardless of whether or not Map<KEY, VAL>
names the current instantiation - the standard does not permit omission of typename
within the definition of a member of a class template before the declarator-id. 因此,无论Map<KEY, VAL>
命名当前实例,该标准都不允许在声明者ID的类模板成员的定义内省略typename
。
This example by Vaughn Cato demonstrates that the behaviour of Clang/GCC is inconsistent, and requires typename
in a similar scenario: 这个例子由沃恩卡托表明锵/ GCC的行为是不一致的,需要typename
类似的情况:
template <typename T>
struct A {
typedef int X;
X f();
};
template <typename T>
A<T>::X A<T>::f() // error: missing 'typename'
{
}
If we conclude that the name Map
is dependent and typename
is required then the template
keyword is also required: 如果我们得出结论,名称Map
是依赖的,并且必须输入typename
,那么还需要template
关键字:
14.2 Names of template specializations [temp.names] 14.2模板专长的名称[临时名称]
When the name of a member template specialization appears after
.
当成员模板专门化名称出现在之后.
or->
in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object or pointer expression of the postfix-expression or the nested-name-specifier in the qualified-id depends on a template parameter (14.6.2) but does not refer to a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. 或->
在postfix-expression中或限定ID中的嵌套名称说明符之后,并且postfix-expression或限定名称中的嵌套名称说明符的对象或指针表达式取决于模板参数(14.6.2),但未引用当前实例(14.6.2.1)的成员,该成员模板名称必须以关键字template为前缀。 Otherwise the name is assumed to name a non-template. 否则,假定该名称命名为非模板。
The corrected example would be: 更正的示例将是:
template<typename KEY, typename VAL>
typename Map<KEY,VAL>::template MapPair<KEY,VAL>
Map<KEY,VAL>::make_map_pair(KEY k, VAL v) {
return MapPair<KEY,VAL>(k,v);
}
There was a discussion of the same issue here: Can typename be omitted in the type-specifier of an out of line member definition? 这里讨论了相同的问题: 超出成员定义的类型说明符中可以省略typename吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.