mercredi 2 octobre 2019

Using a variadic template method of a template class inside a variadic template function [duplicate]

This question already has an answer here:

The following code will not compile in either intel or gcc. The crux of the problem appears to be that a static method variadic template of a template class called with a parameter pack expansion is considered bad syntax on the first pass of the compiler.

template<typename T>
class foo
{
public:
    template <bool do_other_thing_too, typename... ArgTypes>
    static T doThing(ArgTypes... args)
    {
        std::vector<T> outs = { args... };
        T out = 0;
        for (auto V : outs) out += V;
        // the actual code involves templates using SFINAE, and so must either
        // be in this template's parameters or be copied, once for each value 
        // of the bool
        if (do_other_thing_too)
        {
            out *= 1.5;
        }
        return out;
    }
};

struct bar
{
    int data = 3;
    template<bool do_other_thing_too = true, typename T, typename...ArgTypes>
    T& doThings(T& out, ArgTypes... args)
    {
        //the line of the code causing the problem
        out = foo<T>::doThing<do_other_thing_too>(data, args...);
        return out;
    }
};

int main()
{
    bar george;
    int a = 0;
    george.doThings(a, 12, 10.4, 3.2f, 4ll, 2l);
    return 0;
}

It gives the following errors in gcc:

Test.cpp:27:61: error: expected ')' before '...' token
         out = foo<T>::doThing<do_other_thing_too>(data, args...);
                                                             ^
Test.cpp:27:65: error: parameter packs not expanded with '...':
         out = foo<T>::doThing<do_other_thing_too>(data, args...);
                                                                 ^
Test.cpp:27:65: note:         'args'

I have done a decent bit of fiddling with the code, it will not happen if foo's T parameter is folded into foo::doThing's template i.e.

class foo
{
public:
    template <typename T, bool do_other_thing_too, typename... ArgTypes>
    static T doThing(ArgTypes... args)

Also, there is no problem with calling foo<int>::doThing<true>(3, 12, 10.4, 3.2f, 4ll, 2l) directly but neither option is available in the code that spawned this. I have a solution to the problem in the short term do_other_thing_too can be a template parameter in bar, passed by value to foo, and then I can if/else to shove it back into the template that actually needs it, but that is kinda ugly, and I really want to know what is actually causing the problem here.

Aucun commentaire:

Enregistrer un commentaire