33

Es scheint, dass ein Pack-Argument nur anstelle eines Pack-Parameters einer Alias-Vorlage erweitert werden kann. Dies gilt nicht für eine Klasse oder eine Funktionsvorlage:Pack-Erweiterung für Alias-Vorlage

template <class T, class... Args> struct x { using type = T; }; 

template <class T, class... Args> using x_t  = typename x<T, Args...>::type; 
template <class... Args>   using x_fix_t = typename x<Args...>::type; 

template <class... Args> auto f(Args...) -> void { 
    typename x<Args...>::type v1; // OK 
    x_t<Args...> v2; // Error 
    x_fix_t<Args...> v3; // OK 
} 

einfacher Fall:

template <class T, class U> using y_t = T; 

template <class... Args> auto f(Args...) -> void { 
    y_t<Args...> v4; // Error 
} 

Der obige Code erzeugt Fehler mit beiden (auch wenn f nie instanziiert) c++11 und c++14 in g++ 4.9, g++ 5.1 und clang 3.5.

Warum ist das nicht erlaubt und was ist die allgemeine Regel? Ich sehe keinen Grund, dies zu beschränken. Es scheint ein sehr seltsames Verbot zu sein.

Warum nicht als x_fix_t mit der ersten Variante schreiben, ist es klarer, dass x_t ein obligatorisches erstes Argument hat. (Zum Beispiel ist das der Grund, dass f() nicht erlaubt ist). Aber das ist nicht so wichtig, die Lösung ist einfach. Die Frage bleibt: Warum?

gcc Fehler:

error: pack expansion argument for non-pack parameter ‘T’ of 
alias template ‘template<class T, class ... Args> using x_t = typename x::type’ 

Klirren Fehler:

error: pack expansion used as argument for non-pack parameter of 
alias template x_t<Args...> v2; 
+2

Die Info hier ist relevant, ich denke: http://Stackoverflow.com/q/24433658/4326278 – bogdan

+0

Auch, was es wert ist, kompilieren MSVC 12 und 14 RC dies ohne Diagnose (abgesehen von normalen Warnungen für nicht referenziert Variablen) - "Implementierungsvarianz", wie sie sagen. – bogdan

+0

Works OK in g ++ 4.8.2. –

Antwort

14

Dies kompiliert in GCC 4.8 aber nicht in GCC 4.9, die Beweise dafür, dass es zu DR1430 und bug report #59498 in engem Zusammenhang steht. Das Update vorgeschlagen von Roy Chrihfield ist genau das gleiche wie bei Ihnen:

Rewriting the code to use a struct succeeds: 

template <typename T, typename ...> 
struct alias { using type = T; }; 

template <typename ...T> 
using variadic_alias = typename alias<T...>::type; 

Außerdem Jason Merrill erarbeitet, warum es scheitern sollte:

Actually, no, this is very much a Core 1430 issue; there's no way to mangle variadic_alias without mentioning the name of an alias template in the mangling, and they're supposed to be entirely transparent. This only works in 4.8 by accident because checking is disabled for the release.

Keine weitere Diskussion in der Bug-Report vorhanden ist, so dass wir drehen kann DR1430:

Originally, a pack expansion could not expand into a fixed-length template parameter list, but this was changed in N2555. This works fine for most templates, but causes issues with alias templates.

In most cases, an alias template is transparent; when it's used in a template we can just substitute in the dependent template arguments. But this doesn't work if the template-id uses a pack expansion for non-variadic parameters. For example:

template<class T, class U, class V> 
struct S {}; 

template<class T, class V> 
using A = S<T, int, V>; 

template<class... Ts> 
void foo(A<Ts...>); 

There is no way to express A in terms of S, so we need to hold onto the A until we have the Ts to substitute in, and therefore it needs to be handled in mangling.

Currently, EDG and Clang reject this testcase, complaining about too few template arguments for A. G++ did as well, but I thought that was a bug. However, on the ABI list John Spicer argued that it should be rejected.

(See also issue 1558.)

Notes from the October, 2012 meeting:

The consensus of CWG was that this usage should be prohibited, disallowing use of an alias template when a dependent argument can't simply be substituted directly into the type-id.

Additional note, April, 2013:

For another example, consider:

template<class... x> class list{}; 
    template<class a, class... b> using tail=list<b...>; 
    template <class...T> void f(tail<T...>); 

    int main() { 
    f<int,int>({}); 
    } 

There is implementation variance in the handling of this example.

in anderen Worten, dies ist eine laufende Ausgabe ohne Auflösung (Darauf,) in Sicht.

Verwandte Themen