Search code examples
templatesc++17variadic-templatestemplate-argument-deductiongeneric-lambda

Template argument not matched in variadic tuple invoke function


Why can the compiler not match the template parameter F in the invoke() Function. Is there anywhere a non-deduced context I am not aware of?? And how can it be fixed?

Live

// Invoke Function with all tuple arguments.
template<typename F, size_t... Is, typename Tuple>
auto invoke(F&& f, std::index_sequence<Is...>, Tuple&& t)
{
    return f(std::get<Is>(t)...);
}

template<typename F, typename Tuple>
auto invoke(F&& f, Tuple&& t)
{
    constexpr std::size_t uiLength = std::tuple_size_v<std::remove_reference_t<Tuple>>;
    return invoke(std::forward<F>(f),
                  std::make_index_sequence<uiLength>{},
                  std::forward<Tuple>(t));
}

template<typename T>
struct A{
   using D = int;
};
template<typename... T>
auto make(T&...){
    return std::make_tuple(A<T>{}...);
}

int main()
{
  invoke([](auto&, auto&){}, std::make_tuple(A<int>{}, A<double>{})); // works
  //auto a = invoke(make, std::make_tuple(A<int>{}, A<double>{})); // does not compile, but why??
}

Solution

  • Is there anywhere a non-deduced context I am not aware of?? And how can it be fixed?

    The problem is that you can't pass the name of a template function as argument of a function

    template<typename... T>
    auto make(T&...){
        return std::make_tuple(A<T>{}...);
    }
    
    // ...
    
    auto a = invoke(make, std::make_tuple(A<int>{}, A<double>{}));
    

    Try rewriting make() as a generic (and variadic) lambda (that is an object so you can pass it as argument to a function)

    auto a = invoke([](auto & ... rData){ return std::make_tuple(A<decltype(rData)>{}...);},
                    std::make_tuple(A<int>{}, A<double>{}));
    

    Off Topic suggestion: rename invoke() with a different name (myInvoke(), by example) to reduce the risk of a name collision with std::invoke().