Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameter pack expansion fails

Consider the following simplified C++ code:

template <typename ... TEventArgs>
struct Event
{
    // ...
};

template <typename T>
struct Parameter
{
    using Type = T;
    // ...
};

template <typename ... Parameters>
struct Command
{
    Event<typename Parameters::Type...> Invoked;
};

int main()
{
    Command<Parameter<int>, Parameter<float>> c;
}

The Visual Studio C++ compiler (November 2013 CTP, Visual Studio 2013 Update 1) produces the following error: source.cpp(17): error C3546: '...' : there are no parameter packs available to expand

Mingw 4.8.1. on the other hand compiles the code without any problems. Apparently, the Visual Studio compiler has a bug that prevents it from expanding the parameter pack when the expression involves accessing a type of the variadic parameters. Other expansions work, though. For instance, Event<std::vector<Parameters>...> Invoked; compiles successfully or you could even successfully access static members to call a variadic function like this in Command's constructor: SomeVariadicFunc(Parameters::SomeStaticFunc()...);.

So, the questions are:

1) Which compiler is wrong: Visual Studio or mingw? Although I don't see anything that would prevent the typename Parameters::Type parameter pack expansion from working, I'm not 100% sure it's valid C++.

2) Is there a work around? Basically, I would have to perform a projection from a "sequence" of Parameters to a "sequence" of Parameters::Type. Is that possible? I tried to construct that list using a recursive struct but I could only come up with something like myStruct<type1, mystruct<type2, mystruct<type3, ...>>>, which is not what I need.

Thank you for your help.

like image 665
Axel Habermaier Avatar asked Apr 28 '14 17:04

Axel Habermaier


1 Answers

Yakk was able to come up with a workaround for the problem in the comments above. The final version that compiles perfectly with both Visual Studio an mingw is the following:

template <typename ... TEventArgs>
struct Event
{
    // ...
};

template <typename T>
struct Parameter
{
    using Type = T;
    // ...
};

template <typename ... Parameters>
struct Command
{
private:
    // Workaround for the Visual Studio bug
    template<typename T> struct ExpandArgs
    {
        typedef typename T::Type Type;
    };

public:
    Event<typename ExpandArgs<Parameters>::Type...> Invoked;
};

int main()
{
    Command<Parameter<int>, Parameter<float>> c;
}
like image 118
Axel Habermaier Avatar answered Nov 13 '22 12:11

Axel Habermaier