16

Pierwsza część kodu, następnie jakiś kontekst, to pytanie:o zmiennej liczbie argumentów aliasy szablonu jako argumentów szablonu

template <typename T> using id = T; 

template <template <typename...> class F, typename... T> 
using apply1 = F <T...>; 

template <template <typename...> class F> 
struct apply2 
{ 
    template <typename... T> 
    using map = F <T...>; 
}; 

// ... 

cout << apply1 <id, int>() << endl; 
cout << apply2 <id>::map <int>() << endl; 

Zarówno dzyń 3.3 i gcc 4.8.1 skompilować to bez błędu, stosując metafunkcji tożsamość int, więc zarówno wyrażenia oceniają domyślnie int (zero).

Fakt id jest template <typename> podczas apply1, apply2 spodziewać template <typename...> nie dotyczą mnie na pierwszym miejscu. Jednak jest całkiem wygodne, że ten przykład działa, ponieważ inaczej metakunkcje, takie jak apply1, apply2 musiałyby być o wiele bardziej zaangażowane. Z drugiej strony takie aliasy szablonów powodują poważne problemy w kodzie w świecie rzeczywistym, których nie mogę tu odtworzyć: częste błędy wewnętrznego kompilatora dla gcc i rzadsze nieoczekiwane zachowanie dla klang (tylko w bardziej zaawansowanych testach SFINAE).

Po miesiącach prób i błędów, ja teraz zainstalować i wypróbować kodu na (doświadczalnie) gcc 4.9.0, i tu pojawia się błąd:

test.cpp: In instantiation of ‘struct apply2<id>’: 
test.cpp:17:22: error: pack expansion argument for non-pack parameter ‘T’ of alias template ‘template<class T> using id = T’ 
    using map = F <T...>; 
        ^

Ok, więc wydaje się, ten kod nie był jest ważny przez cały ten czas, ale gcc rozbił się na różne sposoby, zamiast zgłaszać błąd. Co ciekawe, podczas gdy apply1, apply2 wydaje się być równoważny, błąd jest zgłaszany tylko dla apply2 (co jest znacznie bardziej przydatne w praktyce). Jeśli chodzi o klang, naprawdę nie mogę powiedzieć.

W praktyce wydaje mi się, że nie mam innego wyjścia, jak pogodzić się z gcc 4.9.0 i poprawić kod, nawet jeśli stanie się on znacznie bardziej złożony.

Teoretycznie chciałbym wiedzieć, co standard mówi: czy ten kod jest ważny? Jeśli nie, to czy nieprawidłowe jest również użycie apply1? lub tylko apply2?

EDIT

Właśnie w celu wyjaśnienia, że ​​wszystkie problemy, jakie miał do tej pory znajdują się aliasy szablonie, a nie elemencie szablonu. Na przykład, należy rozważyć następujące zmiany:

template <typename T> struct id1 { using type = T; }; 

// ... 

cout << typename apply1 <id1, int>::type() << endl; 
cout << typename apply2 <id1>::map <int>::type() << endl; 

To kompiluje i drukuje 0 w obu przypadkach na brzękiem 3.3, GCC 4.8.1, GCC 4.9.0.

W większości przypadków moje obejścia wprowadziły pośredni szablon struct przed aliasem. Jednak teraz próbuję użyć metapunkcji do parametryzowania ogólnych testów SFINAE iw tym przypadku muszę użyć aliasów bezpośrednio, ponieważ nie powinno się tworzyć instancji w structs. Aby uzyskać pewien pomysł, fragment rzeczywistego kodu to here.

+3

Komunikat o błędzie eksperymentalnego GCC 4.9 nie ma dla mnie sensu, a FWIW Myślę, że kod jest prawidłowy. –

+0

Powiązany? http://stackoverflow.com/q/18724698/420683 – dyp

+0

Dzięki, to pytanie jest związane z tym, że szablony zajmujące się specjalnymi przypadkami, takimi jak 'foo',' foo2', 'foo_variadic' itd., są dokładnie tym, co planowałem poprawić kod, jeśli muszę. Jednak, jak już wcześniej edytowałem, moje problemy pojawiają się tylko z aliasami szablonów. – iavr

Odpowiedz

3

ISO C++ 11 14.3.3/1:

A template-argument for a template template-parameter shall be the name of a class template or an alias template, expressed as id-expression.

Plus nie widzę żadnych specjalnych wyjątków dla zmiennej liczbie argumentów parametrów szablonu szablonów.

On the other hand, such template aliases cause serious problems in real-world code that I cannot reproduce here: frequent internal compiler errors for gcc, and less frequent unexpected behavior for clang (only in more advanced SFINAE tests).

Korzeń problemów może być w innych miejscach.Powinieneś spróbować zlokalizować kod, który powoduje wewnętrzny błąd kompilatora - po prostu usuń niepowiązane części jeden po drugim (lub użyj jakiegoś wyszukiwania binarnego, tj. Dziel i zwyciężaj) - i sprawdź, czy błąd nadal występuje na każdym etapie.


Jak dla GCC 4.9.0 błędu, spróbuj zmienić

template <typename... T> 
using map = F <T...>; 

do

template <typename... U> 
using map = F <U...>; 

Może pomogłoby to zrozumieć, co widzi GCC.

+0

Dzięki. Nie udało mi się wyodrębnić kodu, który był błędny w przeszłości, ponieważ usunięcie nawet małych części spowodowało zniknięcie błędów. Z Gcc 4.9 po raz pierwszy mogłem zobaczyć wyraźny komunikat o błędzie, a ja byłem "szczęśliwy", ponieważ jeśli jest prawdziwy, mógłby wyjaśnić prawie wszystko (nawet jeśli każde rozwiązanie będzie brzydkie). W każdym razie, ponieważ problemy nadal istnieją, postaram się zrobić nowy przykład z niespodziewanym wynikiem w innych kompilatorach i wrócić z nowym pytaniem. – iavr

Powiązane problemy