Search code examples
c++gccc++17variadic-templatesdeduction-guide

Variadic template error: 'In instantiation of' (gcc 9.2)


I'm learning about variadic template on c++17 on the Jason Turner's youtube channel then I copy his example code (shown below). In his video he uses the site godbolt.org with the gcc 7.

#include <utility>

template<typename ... B>
struct Merged : B ... {
       template<typename ... T>
       Merged(T&& ... t) : B(std::forward<T>(t))... {}

    using B::operator()...;
};

template<typename ... T>
Merged(T...) -> Merged<std::decay_t<T>...>;

int main() {
    const auto l1 = []() { return 4; };
    const auto l2 = [](const int i) { return i * 10; };

    Merged merged(l1,
                  l2,
                  [](const double d) { return d * 3.2; });

    return 0;
}

I tried the code in my computer with the gcc 9.2 and I got the follow error:

In instantiation of 'Merged::Merged(T&& ...) (with T = {const main()::&, const main()::&, main()::}; B = {}]':

I tried to use the godbolt site to check it out but it also doesn't compile (with gcc 7.1 and gcc 9.2) and give more errors like:

error: missing template arguments before 'merged'Merged merged(l1,

and

error: expected primary-expression before ')' token [](const double d) { return d * 3.2; });

What this error means and what I need to do do fix it?

Compile line in my computer:

g++ -Wall -fexceptions -O2 -pedantic -Wextra -Wall -std=c++1z -m64  -c /home/thearquitect/Desktop/C++/variadic.cpp -o ~/Desktop/obj/variadic.o
g++ -o ~/Desktop/bin/variadic ~/Desktop/obj/variadic.o -s -m64

godbolt try


Solution

  • What this error means and what I need to do do fix it?

    Nothing wrong in your code, as far I understand.

    I suspect a g++ bug.

    To fix it... well... to go around it... don't ask me why but I see that works, for both compilers, require a first template parameter, before the variadic list, for Merged.

    I mean: the following struct

    template <typename B0, typename ... B>
    struct Merged : public B0, public B ...
     {
       template <typename T0, typename ... T>
       Merged (T0 && t0, T && ... t)
          : B0{std::forward<T0>(t0)}, B{std::forward<T>(t)}...
        { }
    
       using B0::operator();
       using B::operator()...;
    };
    

    together with the following deduction guide

    template <typename T0, typename ... T>
    Merged (T0, T ...) 
       -> Merged<std::decay_t<T0>, std::decay_t<T>...>; 
    

    works with both compilers.

    Also your original deduction guide works with the modified struct.

    -- EDIT --

    I see that you can also solve the problem (compiling with both compilers) maintaining the struct with only the variadic list

    template <typename ... B>
    struct Merged: public B ...
     {
       template <typename ... T>
       Merged (T && ... t)
          : B{std::forward<T>(t)}...
        { }
    
       using B::operator()...;
    };
    

    and using a deduction guide with a required argument

    template <typename T0, typename ... T>
    Merged (T0, T ...) 
       -> Merged<std::decay_t<T0>, std::decay_t<T>...>;