Pack expansion for alias template
This compiles in GCC 4.8 but fails in GCC 4.9, which is evidence that it's related to CWG 1430 and bug report #59498. The fix proposed by Roy Chrihfield is the exact same one as yours:
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;
Furthermore, Jason Merrill elaborates on why it should fail:
Actually, no, this is very much a Core 1430 issue; there's no way to
mangle variadic_alias<T...> 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.
No further discussion exists in the bug report, so we can turn to CWG 1430:
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<Ts...> 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 otherwords, this is an on-going issue without any resolution (AFAIC) in sight.
Unpacking parameter packs in template aliases
It was reported in gcc4.9 bugzilla:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
Minimal code to reproduce
template <typename T, typename ...>
using alias = T;
template <typename ...T>
using variadic_alias = alias<T...>;
using Fail = variadic_alias<int>;
int main() { }
From the explanation from gcc folks - it is not so obvious this is a real bug.
This is still discussion held in gcc bugzilla and in DR 1430 (http://open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430) - summary in now in the question above.
Workaround for passing parameter pack to alias templates (which have non-pack parameters)
Workaround is to make the alias variadic:
struct Bar1 {
template <typename... Ts>
using Foo = Foo1<Ts...>;
};
struct Bar2 {
template <typename... Ts>
using Foo = Foo2<Ts...>;
};
Demo
aliassing a template parameter pack
You cannot alias variadic template argument. You can wrap them in std::tuple
:
template <typename FirstArg, typename ... OtherArgs>
struct Base {
using UsableFirstArg = FirstArg;
using UsableOtherArgs = std::tuple<OtherArgs...>;
virtual OtherClass method(OtherArgs... a) = 0;
};
Unwrapping need some helpers:
template <typename DerivedOfBaseInstantiation,
typename = typename DerivedOfBaseInstantiation::UsableOtherArgs>
struct CallerStructure;
template <typename DerivedOfBaseInstantiation, typename ... OtherArgs>
struct CallerStructure<DerivedOfBaseInstantiation, std::tuple<OthersArgs...>> {
OtherClass knownCall(typename DerivedOfBaseInstantiation::UsableFirstArg a) {
DerivedOfBaseInstantiation instance;
return instance.someMethod(a);
}
OtherClass unknownCall(OtherArgs... args) {
DerivedOfBaseInstantiation instance;
return instance.method(args...);
}
};
C++ 11 Templates, Alias for a parameter pack
You probably want this:
template <typename ...P> struct parameter_pack
{
template <template <typename...> typename T> using apply = T<P...>;
};
// Example usage:
struct A {};
struct B {};
struct C {};
template <typename...> struct S {};
using my_pack = parameter_pack<A, B, C>;
my_pack::apply<S> var; // Equivalent to `S<A, B, C> var;`.
In your case it could be used like this:
class EntityExtra : public DerivedA<int>, DerivedA<char>, DerivedB<float>{
public:
using desiredBases = parameter_pack<Base<int>, Base<char>, Base<float>>;
};
// ...
EntityExtra::desiredBases::apply<BaseManager> bm;
// Creates `BaseManager<Base<int>, Base<char>, Base<float>> bm;`.
Syntax of '...' with Parameter Pack Expansion using std::forward
The ...
applies to the thing on its left.
function(params...)
expands to
function(param1, param2, ..., paramN)
.function(std::forward<Tys>(params)...)
expands to
function(std::forward<Tys1>(param1), std::forward<Tys2>(param2), ..., std::forward<TysN>(paramN))
function(std::forward<Tys>(params...))
expands to
function(std::forward<Tys>(param1, param2, ..., paramN))
template parameter pack in using
Since it's a known MSVC bug, if you still want to make this work with MSVC you'll have to do it the (not very) hard way:
template <typename ...Types>
struct TC;
template <typename T>
struct TC<T> : TA<T>
{
using TA<T>::foo;
};
template <typename T, typename ...Types>
struct TC<T, Types...> : public TC<T>, public TC<Types...>
{
using TC<T>::foo;
using TC<Types...>::foo;
};
Related Topics
Error for Hash Function of Pair of Ints
Checking If Two Cubic BéZier Curves Intersect
Portable Compare and Swap (Atomic Operations) C/C++ Library
Iterating Through a Lua Table from C++
How to Implement Lock Free Map in C++
Default Visibility of C++ Class/Struct Members
How to Iterate Over a Constant Vector
A Simple Hello World Npapi Plugin for Google Chrome
How to Safely Average Two Unsigned Ints in C++
Qt/Qml:Send Qimage from C++ to Qml and Display the Qimage on Gui
Idiomatic Way to Declare C++ Immutable Classes
Differences Between Running an Executable with Visual Studio Debugger VS Without Debugger
Maximum Number of Parameters in Function Declaration
Windows & C++: Extern & _Declspec(Dllimport)