Синтаксис C ++ для вызова шаблонной статической функции-члена внутреннего класса? - PullRequest
4 голосов
/ 19 января 2010

У меня есть некоторый шаблонный код, который прекрасно компилируется в 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;
}

Кто-нибудь знает, что я делаю не так?

Ответы [ 4 ]

4 голосов
/ 19 января 2010

Я получаю его для компиляции:

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;
}
4 голосов
/ 19 января 2010

Вы должны сообщить компилятору, что зависимое имя R является шаблоном:

template< typename C >
S<C> & foo( S<C> & s, const int n ) {
    S<C>::template R<16>::append( s, n );
    return s;
}
2 голосов
/ 19 января 2010

Использование 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

На ту же тему, если вы делаете что-то вроде:

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-парсинга.

0 голосов
/ 19 января 2010

Попробуйте написать "const int N" в структуре R :: append, а затем используйте N (а не 42?).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...