vendredi 23 septembre 2016

extra template argument causes overload ambiguity

I'm trying to extract details of a function template as a template argument.

#include <tuple>

template <typename T>
struct Generator
{
    typedef int type;
    int operator()(int i) const { return i; }
};

// old functions
template <
    typename... Args,
    typename... FArgs>
std::tuple<Args...> g(
    std::tuple<Args...> & a,
    FArgs&&... fargs)
{
    return std::make_tuple( (Generator<Args>()(fargs...))... );
}

template <
    typename Arg,
    typename... FArgs>
std::tuple<Arg> g(
    std::tuple<Arg> & a,
    FArgs&&... fargs)
{
    return std::make_tuple( (Generator<Arg>()(std::forward<FArgs>(fargs)...)) );
}

// new functions
template <
    template <typename T> class F,
    typename... Args,
    typename... FArgs>
std::tuple<Args...> h(
    std::tuple<Args...> & a,
    FArgs&&... fargs)
{
    return std::make_tuple( (F<Args>()(fargs...))... );
}

template <
    template <typename> class F,
    typename Arg,
    typename... FArgs>
std::tuple<Arg> h(
    std::tuple<Arg> & a,
    FArgs&&... fargs)
{
    return std::make_tuple( (F<Arg>()(std::forward<FArgs>(fargs)...)) );
}

int main()
{
    auto t = std::make_tuple( 1 );
    auto y = g(t, 2);
    auto z = h<Generator>(t, 2);  // ERROR
}

It compiles fine with clang, but using gcc (4.9, 5.3, and 6.2) I get the following error:

% g++ --std=c++11 test.cc
test.cc: In function ‘int main()’:
test.cc:56:28: error: call of overloaded ‘h(std::tuple<int>&, int)’ is ambiguous
  auto z = h<Generator>(t, 2);
                            ^
test.cc:34:21: note: candidate: std::tuple<_Elements ...> h(std::tuple<_Elements ...>&, FArgs&& ...) [with F = Generator; Args = {int}; FArgs = {int}]
 std::tuple<Args...> h(
                     ^
test.cc:45:17: note: candidate: std::tuple<Arg> h(std::tuple<Arg>&, FArgs&& ...) [with F = Generator; Arg = int; FArgs = {int}]
 std::tuple<Arg> h(

Should this be ambiguous? If so, why isn't the call to g also ambiguous?

Aucun commentaire:

Enregistrer un commentaire