代码之家  ›  专栏  ›  技术社区  ›  jwfearn

C++语法调用模板内部类静态成员函数?

  •  4
  • jwfearn  · 技术社区  · 15 年前

    我有一些模板代码,在VC9(微软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;
    }
    

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

    4 回复  |  直到 15 年前
        1
  •  2
  •   Matthieu M.    15 年前

    在使用了Visual Studio和GCC之后,这是一个众所周知的问题:)我使用了VS2003和GCC 3.4.2,所以有一段时间是这样的。

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

    GCC的行为如标准所述,并执行两个解析:

    • 第一次遇到模板时,没有关于类型的任何信息,此时需要一些 typename template 帮助理解发生了什么的魔法
    • 用给定类型实际实例化模板时的第二秒钟

    另一方面,VS在实例化时只进行一次解析,因此可以完全解析符号而不需要 类别名 模板 到处都是。

    对于方法,您有相同的东西:

    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方案。

        2
  •  4
  •   Magnus Hoff    15 年前

    我让它编译为:

    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;
    }
    
        3
  •  4
  •   sth Alien    15 年前

    您必须告诉编译器依赖名称 R 是模板:

    template< typename C >
    S<C> & foo( S<C> & s, const int n ) {
        S<C>::template R<16>::append( s, n );
        return s;
    }
    
        4
  •  0
  •   user231967    15 年前

    尝试在结构r::append中写入“const int n”,然后使用n(而不是42?).