samedi 4 novembre 2017

Wrong pack expanded in variadic template

I got a very strange problem with variadic templates. It seems the wrong pack is expanded. Here's a code snippet:

#include <tuple>

template<typename...>
struct types {};

template<typename = types<>>
struct Base;

template<typename... Args1>
struct Base<types<Args1...>> {
    template<typename... Args2>
    static auto construct(Args1... args1, Args2&&... args2)
        -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...))
    {
        return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...);
    }
};

struct Derived : Base<> {};

int main() {
    auto test = &Derived::construct<char const(&)[7]>;
}

I get this error:

13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]'
         -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...))
                                     ~~~~~~^~~~~~~
13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]'
<source>: In function 'int main()':
22 : <source>:22:27: error: unable to deduce 'auto' from '& construct<const char (&)[7]>'
     auto test = &Derived::construct<char const(&)[7]>;
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
22 : <source>:22:27: note:   could not resolve address from overloaded function '& construct<const char (&)[7]>'
Compiler exited with result code 1

However, it don't happen when the pack has values in it:

struct HasForward { int forward() { return 0; }};

struct Derived : Base<types<HasForward>> {};

Here's the First snippet live and the Second snippet live

What's wrong with this code? Is this a compiler bug? Is there any ways to overcome it and leave the first pack empty?

Aucun commentaire:

Enregistrer un commentaire