Search code examples
c++c++11templatesvariadic-templatestemplate-argument-deduction

Deducing Arguments Failure for Variadic Template Function


This seems like a standard case:

#include <iostream>
#include <vector>
#include <utility>
#include <tuple>

using namespace std;

template <typename... T>
using VType = vector<tuple<T...>>;

template <typename... T>
void Foo(const T&... t, VType<T...>* v) {
    v->push_back(std::make_tuple(t...));
}
int main() {
    // your code goes here
    VType<string, string> foo;
    Foo(string("asdf"), string("qwerty"), &foo);
    return 0;
}

If you explicitly tell the compiler Foo<string, string> it works fine, it fails to deduce with:

error: no matching function for call to ‘Foo(std::__cxx11::string, std::__cxx11::string, VType<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >*)’

This function works as expected:

template <typename... T>
void Bar(const std::tuple<T...> t, VType<T...>* v) {
  v.push_back(t); 
}

Solution

  • The types of a variadic list of arguments can be deduced only in last position.

    So

    template <typename... T>
    void Foo(VType<T...>* v, const T&... t) {
        v->push_back(std::make_tuple(t...));
    }
    

    works because the t ... arguments are in last position where

    template <typename... T>
    void Foo(const T&... t, VType<T...>* v) {
        v->push_back(std::make_tuple(t...));
    }
    

    give error because t... isn't in last position.

    Solution: modify Foo() to receive the pointer to vector argument v in first position and call Foo() as follows

    Foo(&foo, string("asdf"), string("qwerty"));