我有一些模板代码可以在VC9(Microsoft Visual C ++ 2008)中编译好,但不能在GCC 4.2(在Mac上)编译。我想知道是否有一些我缺少的语法魔法。
下面我有一个精简的示例,演示了我的错误。对不起,如果这个例子看起来毫无意义,我尽可能地删除了这个错误。
特别是我有一个模板类S,它有一个内部类R,它也是一个模板类。从顶级模板函数foo,我试图调用R :: append这是R的静态成员函数:
template< typename C >
struct S {
template< typename T >
S<C> & append( const T & ) { return *this; }
template< int B >
struct R {
template< typename N >
static S<C> & append( S<C> & s, const N ) {
return s.append( 42 );
}
};
};
template< typename C >
S<C> & foo( S<C> & s, const int n ) {
S<C>::R<16>::append( s, n ); // error: '::append' has not been declared
return s;
}
那里的任何人都知道我做错了什么?
答案 0 :(得分:4)
我用它来编译:
template< typename C >
S<C> & foo( S<C> & s, const int n ) {
typedef typename S<C>::template R<16> SR;
SR::append( s, n );
return s;
}
答案 1 :(得分:4)
您必须告诉编译器,从属名称R
是一个模板:
template< typename C >
S<C> & foo( S<C> & s, const int n ) {
S<C>::template R<16>::append( s, n );
return s;
}
答案 2 :(得分:2)
同时使用Visual Studio和gcc,这是一个已知的问题:)我使用了VS2003和gcc 3.4.2所以它已经有一段时间了。
如果我没记错的话,问题是由于在这些编译器上解析模板的方式。
gcc的行为与标准相同,并执行2次解析:
typename
和template
魔术来帮助理解正在发生的事情typename
和template
的符号。
你对方法有同样的看法:
template <class Item>
struct Test
{
template <class Predicate>
void apply(Predicate pred);
void doSomething { this->apply(MyPredicate()); } // Visual Studio
void doSomething { this->template apply(MyPredicate()); } // gcc
}; // struct Test
在同一主题上,如果您执行以下操作:
template <class Item>
struct Test { static const std::string Name; };
您需要为模板的每个实例化实际定义此static
属性,否则您将拥有未定义的符号。
VS接受这种语法:
const std::string Test<MyType>::Name = "MyType";
但是gcc要求一个小关键字:
template <> const std::string Test<MyType>::Name = "MyType";
你可能会认为VS更好,因为它要求你少,但另一方面,gcc可能会在你第一次解析它们时(即没有任何实际的实例化)警告你模板方法/类中的错误而且就个人而言,越快越好。
显然,好消息是如果在gcc上编译(对于这些问题),它也可以在Visual Studio上正常编译。
由于我不是标准人,但我不确定该标准是否实际要求或建议2-parses方案。
答案 3 :(得分:0)
尝试在struct R :: append中编写“const int N”,然后使用N(而不是42?)。