16

Zuerst einige Code, dann einiger Kontext, dann ist die Frage:Variadische Vorlage Aliasnamen als Template-Argument

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; 

Beiden Klirren 3.3 und gcc 4.8.1 dies ohne Fehler kompilieren, um die Identität metafunction zu int Anwendung, so dass beide Ausdrücke bewerten zu einem Standard int (Null).

Die Tatsache, dass id a template <typename> während apply1 erwarten apply2 ein template <typename...> tat mir Sorge in erster Linie. Es ist jedoch ziemlich praktisch, dass dieses Beispiel funktioniert, weil andernfalls Metafunktionen wie apply1, apply2 so viel mehr beteiligt sein müssten.

Auf der anderen Seite verursachen solche Template-Aliase ernsthafte Probleme im realen Code, die ich hier nicht reproduzieren kann: häufige interne Compiler-Fehler für gcc und weniger häufiges unerwartetes Verhalten für clang (nur in fortgeschritteneren SFINAE-Tests).

Nach Monaten der Versuch und Irrtum, ich jetzt installieren und versuchen, den Code auf der (experimentell) gcc 4.9.0, und hier kommt der Fehler:

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, so scheint es, dieser Code nicht war die ganze Zeit gültig, aber gcc stürzte auf verschiedene Arten ab, anstatt den Fehler zu melden. Interessanterweise, während apply1, apply2 als äquivalent erscheinen, wird der Fehler nur für apply2 gemeldet (was in der Praxis viel nützlicher ist). Was den Klang betrifft, kann ich wirklich nicht sagen.

In der Praxis scheint es, als ob ich nicht anders als mit gcc 4.9.0 zu gehen und den Code zu korrigieren, obwohl es viel komplexer werden wird.

In der Theorie würde ich gerne wissen, was der Standard sagt: Ist dieser Code gültig? Wenn nicht, ist die Verwendung von apply1 auch ungültig? oder nur apply2?

EDIT

Nur um zu klären, dass alle Probleme, die ich bisher auf Vorlage Aliase verweisen gehabt haben, nicht Vorlage structs. Betrachten wir zum Beispiel die folgende Änderung:

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

// ... 

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

Dies kompiliert fein und Drucke 0 in beiden Fällen auf Klirren 3.3, gcc 4.8.1, gcc 4.9.0.

In den meisten Fällen haben meine Problemumgehungen eine Zwischenschablonenstruktur vor dem Alias ​​eingeführt. Ich versuche jedoch, Metafunktionen zu verwenden, um generische SFINAE-Tests zu parametrisieren, und in diesem Fall muss ich Aliase direkt verwenden, da Strukturen nicht instanziiert werden sollten. Nur um eine Idee zu bekommen, ist ein Stück des tatsächlichen Codes here.

+3

Die Fehlermeldung des experimentellen GCC 4.9 macht für mich keinen Sinn, und FWIW Ich denke, der Code ist gültig. –

+0

In Verbindung stehend? http://StackOverflow.com/q/18724698/420683 – dyp

+0

Danke, diese Frage ist in Bezug darauf, dass Vorlagen mit Sonderfällen wie 'foo',' foo2', 'foo_variadic' etc. genau die Art und Weise sind, die ich plante zu korrigieren der Code, wenn ich muss. Wie ich oben bearbeitet habe, erscheinen meine Probleme jedoch nur bei Vorlagenaliasnamen. – iavr

Antwort

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 I keine besonderen Ausnahmen für variadische Template-Template-Parameter.

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).

Wurzel der Probleme kann an anderen Orten sein.Sie sollten versuchen, Code zu lokalisieren, der einen internen Compilerfehler verursacht - entfernen Sie einfach nicht zusammenhängende Teile einzeln (oder verwenden Sie irgendeine Art von Binärsuche, d. H. Teilen und Herrschen) - und prüfen Sie, ob der Fehler immer noch in jeder Phase vorhanden ist.


Was GCC 4.9.0 Fehler, versuchen

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

zu

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

Vielleicht würde dies helfen zu verstehen, zu ändern, was GCC sieht.

+0

Danke. Ich war nicht in der Lage, den Code, der in der Vergangenheit fehlerhaft war, zu isolieren, weil das Entfernen selbst kleiner Teile die Fehler verschwinden ließ. Mit gcc 4.9 war dies das erste Mal, dass ich eine klare Fehlermeldung sehen konnte, und ich war "glücklich", denn wenn es wahr ist, könnte es fast alles erklären (obwohl jede Lösung hässlich ist). Wie auch immer, da die Probleme immer noch da sind, werde ich versuchen, ein neues Beispiel mit unerwartetem Ergebnis in anderen Compilern zu machen und mit einer neuen Frage zurückkommen. – iavr