Внутренний класс в зависимости от аргумента шаблона - PullRequest
2 голосов
/ 24 марта 2011

Рассмотрим следующий пример:

#include <iostream>
#include <typeinfo>

template< int N, typename T >
struct B
{
    struct C;
};

template< typename T >
struct B< 0, T >::C
{
    typedef T type;
};

template< int N, typename T >
struct B< N, T >::C
{
    typedef T type[N];
};

int main()
{
    std::cout<<"n=0   type = " << typeid( B< 0, float >::C::type ).name() << std::endl;
    std::cout<<"n=5   type = " << typeid( B< 5, float >::C::type ).name() << std::endl;
}

При компиляции с использованием g ++ (версия 4.3.0)

g++ dfg.cpp  -ansi -pedantic -Wall

ошибка компиляции:

dfg.cpp:13: error: qualified name does not name a class before ‘{’ token
dfg.cpp: In instantiation of ‘B<0, float>::C’:
dfg.cpp:25:   instantiated from here
dfg.cpp:20: error: ISO C++ forbids zero-size array

ЧтоЯ действительно пытаюсь архивировать, чтобы иметь различную реализацию Imp в зависимости от значения перечисления (в примере вместо перечисления я использовал int, но это не должно иметь значения).

Может кто-нибудь объяснить, почемуэто не разрешено?Почему я получаю первую ошибку?(этот: квалифицированное имя не называет класс до токена '{')


Что касается реализации pimpl в зависимости от параметра шаблона, я создал новый вопрос (с лучшим примером) здесь

Ответы [ 2 ]

3 голосов
/ 24 марта 2011

Это недействительно:

template< typename T >
struct B< 0, T >::C
{
    typedef T type;
};

Вы можете специализировать элементы шаблонов классов, но только для неявных реализаций этих шаблонов классов. Это означает на простом английском языке: только если вы задаете значения для всех аргументов шаблона включающего шаблона класса (член которого вы должны специализировать).

template< >
struct B< 0, int >::C
{
    typedef T type;
};

То, что вы написали, это определение B<0, T>::C, которое является членом частичной специализации шаблона класса B<N, T>. Такой частичной специализации не существует, поэтому компилятор допустил ошибку.


У вас есть несколько вариантов решения этой проблемы. Одним из них является

template< int N, typename T >
struct B
{
    template<typename N1, typename T1>
    struct CMember { typedef T1 type[N1]; };

    template<typename T1>
    struct CMember<0, T1> { typedef T1 type; };

    struct C { 
      typedef typename CMember<N, T>::type type;
    };
};

Обратите внимание, что явные специализации (не частичные) не могут быть непосредственно вставлены в шаблон класса (поэтому template<> struct CMember<0, int> { ... } будет неправильно сформирован при записи в теле B). Тогда вам потребуется определить шаблон «селектор» вне B (возможно, в пространстве имен detail).

Другие альтернативы включают наследование от CMember и наследование его typedefs.

2 голосов
/ 24 марта 2011

Вы не можете определить C за пределами B таким образом - C не существует для B специализации, которую вы создаете.Если вы хотите специализировать B :: C, вам нужно специализировать B. Вы пытаетесь сделать следующее?

template< int N, typename T >
struct B
{
    struct C {
        typedef T type[N];
    };
};

template< typename T >
struct B< 0, T >
{
    struct C {
        typedef T type;
    };
};

В качестве альтернативы вы можете сделать что-то вроде:

template< int N, typename T >
struct B
{
    struct C;
};

template< typename T >
struct B< 0, T > {
    struct C;
};

template< typename T >
struct B< 0, T >::C
{
    typedef T type;
};

template< int N, typename T >
struct B< N, T >::C
{
    typedef T type[N];
};

Это частично специализирует B на 0 и форвард объявляет C, так что B<0, T>::C может быть определено.

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