2015-09-07 12 views
7

Jestem pewien, że znam już odpowiedź na to pytanie, ale warto spróbować.Czy mogę zadeklarować specjalizację szablonu z listy typów?

Tak, że mam typelist:

template <typename ...Ts> 
struct typelist{}; 

który zawiera kilka obiektów:

struct foo{}; 
struct bar{}; 
struct quux{}; 

using objects = typelist<foo, bar, quux>; 

teraz mam szablonie klasy (baz), który może podjąć każdą z tych obiektów. Ale ze względu na rozmiar kodu i czas kompilacji, chcę mieć implementację mojej szablonowej metody w pliku cpp.

Więc na dole baz.cpp mam:

template <> class baz<foo>; 
template <> class baz<bar>; 
template <> class baz<quux>; 

Problemem jest to, że mają wiele zajęć jak baz, a lista obiektów, które pracują z również zawsze się zmienia. A więc ... czy w każdym razie mogę zachować moją pojedynczą typelistę obiektów i użyć tego w pliku cpp każdego obiektu, który specjalizuje się w baz? Następnie wszystko, co muszę zrobić, to zaktualizować moją listę typów, gdy mam nowy obiekt i wszystkie pliki obiektów zostaną odbudowane.

+0

Nie trzeba * wyspecjalizować *, tylko jawnie * tworzyć ich *. – Jarod42

+0

Można to zdecydowanie zrobić za pomocą makra. Biorąc pod uwagę, że będzie to izolowane od reszty twojego kodu, dlaczego nie po prostu to zrobić? –

Odpowiedz

9

Linia przednia-template <> class baz<foo>; deklaruje specjalizację, a nie instancję szablonu, co, jak przypuszczam, jest tym, czego potrzebujesz.

Nie sądzę, że istnieje bezpośredni sposób, aby to zrobić, będziesz musiał wykonać pewne metaprogramowanie. Można użyć Boost.Preprocessor wygenerować wszystkie potrzebne kod:

#define TYPES (foo)(bar)(quux) 

using objects = typelist< BOOST_PP_SEQ_ENUM(TYPES) >; 

// Generate extern template declarations in the header 
#define EXTERN_TEMPLATE_BAZ(r, data, arg)\ 
    extern template class baz<arg>; 

BOOST_PP_SEQ_FOR_EACH(EXTERN_TEMPLATE_BAZ, _, TYPES) 

// Generate template instantiations in the .cpp 
#define TEMPLATE_BAZ(r, data, arg)\ 
    template class baz<arg>; 

BOOST_PP_SEQ_FOR_EACH(TEMPLATE_BAZ, _, TYPES) 

Nie może być sposób to zrobić bez preprocesora, ale robi to byłoby nałożyć dodatkowe wymagania dotyczące rodzaju baz. Chodzi o to, aby użyć typu w kontekście, w którym ma być utworzony instancja, w tym wszystkie jego metody.

+0

Nie każdy używa doładowania i nie ma żadnej wzmianki o zwiększeniu w pytaniu. –

+2

Tak? Jest to jednak prawidłowe rozwiązanie. –

+0

To rozwiązanie działa, ale może to nie jest to, czego żądał pytający. Zwiększenie nie jest częścią standardowego C++. –

3

Jestem prawie pewien, że to niemożliwe bez użycia preprocesora. Możesz być w stanie zrekonstruować pakiet argumentów szablonu z argumentu, ale musisz przekazać instancję argumentu, która wydaje się być nieoptymalna. Po drugie, jawne instancje szablonów nie są dozwolone w zakresie bloku (tj. W funkcji szablonu), więc nie ma możliwości napisania szablonu, który jawnie tworzy inny szablon.

Jak wskazuje Nir, może po prostu użyć numeru X Macro?

#define MY_FOREACH_TYPES(func, ...) \ 
    func(type1, ##_VA_ARGS__) \ 
    func(type2, ##_VA_ARGS__) \ 

#define MY_INSTANTIATE(Type, Class) \ 
    template <> class Class<Type>; 

MY_FOREACH_TYPES(MY_INSTANTIATE, bar) 

Teraz zaktualizuj tylko MY_FOREACH_TYPES, gdy zmieni się lista typów.

+0

Dziękuję bardzo za wzmiankę o X-Macro. Link wiki jest najlepszy! Czy wiesz, co powstrzymuje ludzi przed używaniem X Macro? (z wyjątkiem, że trudniej jest śledzić/debugować). – javaLover

2

Wersja pracować ze zwykłym preprocesora

//Header file 

#define BAZ_OBJS \ 
    BAZ_BEGIN foo \ 
    BAZ_AND  bar \ 
    BAZ_AND  quux \ 
    BAZ_END 

#define BAZ_BEGIN 
#define BAZ_AND , 
#define BAZ_END 
using objects = typelist<BAZ_OBJS>; 
#undef BAZ_BEGIN 
#undef BAZ_AND 
#undef BAZ_END 

#define BAZ_BEGIN BAZ_EXTERN template class baz< 
#define BAZ_END >; 
#define BAZ_AND BAZ_END BAZ_BEGIN 

#ifdef MY_IMPLEMENTATION_CPP //cpp should define it before including the header file 
#define BAZ_EXTERN 
#else 
#define BAZ_EXTERN extern 
#endif 

BAZ_OBJS 
3

Pierwsze rzeczy pierwsze: poprawnej składni o wyraźną klasy szablonu konkretyzacji jest

template class baz<foo>; 
template class baz<bar>; 
template class baz<quux>; 
nie

template <> class baz<foo> co jest jednoznaczne klasy szablonu specjalizacji (forward-deklaracja).

Jedną z możliwości mogłoby być wystąpienia klasy, który wygląda tak

template <template <typename> class T, typename... Args> 
class for_each_class : T<Args>... 
{ 
}; 

// Instantiate 
template class for_each_class<baz, foo, bar, quux>; 

która zmusiłaby niejawny konkretyzacji baz<foo>, baz<bar>, baz<quux>. Cóż, ale chcesz to zrobić z typelist. typelist jest już wyspecjalizowanym szablonem i nie ma możliwości w C++ do iterowania za pomocą parametrów szablonu w typelist z "zewnętrznego świata typelist".

Inną możliwością może być użycie makra, ale nawet w makro nie można użyć oryginalnego typelist. Podsumowując, Twój problem nie ma rozwiązania z podanym typelist.

Jako rozwiązanie pozostawiłbym instancję szablonu w kompilatorze, jeśli to możliwe. Niewykorzystane szablony nie są w tym przypadku tworzone. Powolna kompilacja wynika ze sposobu, w jaki meta-programs are specified.

+0

To nie tworzy instancji 'baz ', 'baz ' lub 'baz '. – Barry

+0

Ponieważ elementy będące szablonami nie są tworzone instancjami. – Barry

+0

@Barry Proszę ponownie przeczytać mój wpis. Nie mówię, że to stworzy instancję 'baz ' itd., Ale wyjaśniam, dlaczego nie można tego zrobić bez makra. –

1

To by załatwiło sprawę. Ostatecznie z secialization typelist z tylko jednym (lub żaden) typy.

template <typename Head, typename ...Tail> 
struct typelist{ 
    typedef baz<Head> head_t; 
    typedef typelist<Tail...> tail_t; 
}; 
+0

Nie, nie tworzy instancji 'baz'. –

+0

Co jeśli 'baz ' był atrybutem 'typelist '? Obecnie nie jestem w stanie go przetestować; najnowszym kompilatorem, jaki otrzymałem, jest gcc4.3. – prgasp77

+0

Jaki atrybut? Nie jestem świadomy żadnych atrybutów, które wykonują instancję szablonu. –

Powiązane problemy