C++;调用模板化内部类静态成员函数的语法? 我有一些模板代码,它编译VC9(微软Visual C++ 2008)中的Frand,但不会在GCC 4.2(在MAC上)编译。我想知道我是否缺少一些句法上的魔力

C++;调用模板化内部类静态成员函数的语法? 我有一些模板代码,它编译VC9(微软Visual C++ 2008)中的Frand,但不会在GCC 4.2(在MAC上)编译。我想知道我是否缺少一些句法上的魔力,c++,macos,templates,gcc,C++,Macos,Templates,Gcc,下面我有一个简单的例子来说明我的错误。很抱歉,如果这个例子看起来毫无意义,我会尽可能地删除它来隔离这个错误 特别是我有一个模板类S,它有一个内部类R,它也是一个模板类。从顶级模板函数foo,我尝试调用R::append,它是R: template< typename C > struct S { template< typename T > S<C> & append( const T & ) { return *this; }

下面我有一个简单的例子来说明我的错误。很抱歉,如果这个例子看起来毫无意义,我会尽可能地删除它来隔离这个错误

特别是我有一个模板类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;
}
模板
结构{
模板
附加(const T&){return*this;}
模板
结构R{
模板
静态S&append(S&S,常量N){
返回s.append(42);
}
};
};
模板
S&foo(S&S、const int n){
S::R::append(S,n);//错误:“::append”尚未声明
返回s;
}

有人知道我做错了什么吗?

试着在struct R::append中编写“const int N”,然后使用N(而不是42?)。

我用以下方法编译它:

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;
}
模板
S&foo(S&S、const int n){
typedef typename S::template R SR;
附加(s,n);
返回s;
}

您必须告诉编译器从属名称
R
是一个模板:

template< typename C >
S<C> & foo( S<C> & s, const int n ) {
    S<C>::template R<16>::append( s, n );
    return s;
}
模板
S&foo(S&S、const int n){
模板R::追加(S,n);
返回s;
}

既使用了Visual Studio又使用了gcc,这是一个众所周知的问题:)我使用了VS2003和gcc 3.4.2,所以这已经有一段时间了

如果我没记错的话,问题是由于在这些编译器上解析模板的方式

gcc的行为如标准所述,并执行2次解析:

  • 第一次遇到模板时,没有任何类型信息,此时需要一些
    typename
    template
    魔术来帮助理解发生了什么
  • 第二种方法是使用给定类型实际实例化模板
另一方面,VS在实例化时只进行一次解析,因此可以完全解析符号,而不必到处使用
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
但gcc需要一个小关键词:

template <> const std::string Test<MyType>::Name = "MyType";
template const std::string Test::Name=“MyType”;
您可能会认为VS更好,因为它对您的要求更少,但另一方面,gcc可能会在第一次解析模板方法/类时(即没有任何实际实例化)就警告您模板方法/类中的错误,而且越快越好

显然,好消息是,如果在gcc上编译(针对这些问题),那么它在visualstudio上也会编译得很好


<> P>因为我不是标准差,我不确定标准是否真正地要求或建议2个解析方案。< /P> + 1,我想知道这是VisualStudio中的一个bug还是GCC中的一个bug。显然这是VisualC++的非标准“特征”。C++规范说在这种情况下需要消歧。VC让你跳过它。我想知道VC是否有一个编译器开关,使其更严格地执行规范遵从性?所以你认为VC接受原始代码是不符合规范的?谢谢你的帮助。这确实修复了我在Mac上的错误。我也修复了我的实际项目,现在它可以在Mac和PC上运行。我不确定哪个编译器更符合我的要求。@Terry:我发布了一个答案来解释这个问题。我认为gcc实际上在这一点上更加一致,但我可能错了。typedef不是必需的,但我也更喜欢别名复杂类型,即使我只使用一次,为了清晰起见。该标准确实要求对非依赖和依赖名称进行两阶段查找。有人有一个胶水,哪个MSVC版本放弃了这种模糊性并实现了该标准?显然,这些代码可能需要有问题的宏,以便不仅在平台之间,而且在MSVC版本之间保持可移植性。
const std::string Test<MyType>::Name = "MyType";
template <> const std::string Test<MyType>::Name = "MyType";