Search code examples
c++windowsc++14variadic-templatesstdtuple

std::tuple duplicate type T in get<T>(tuple) - Compile time assertion failure


I am storing the variadic arguments to an object constructor inside a std::tuple and so far so good. But when calling an object function using the stored arguments and std::get<>(), I will be thrown a compile-time assertion failure that I simply don't understand. This will happen only when all arguments are not each of a different type.

The compiler error message is:

msvc\14.16.27023\include\tuple(934): error C2338: duplicate type T in get(tuple)

mcve below:

#include <tuple>
#include <iostream>

using namespace std;

template<class... Args>
struct store_in_tuple {

    tuple<Args...> m_tuple_args;

    store_in_tuple(Args... args) : m_tuple_args{ args... } {}

    void func() {
        func_tuple(std::get<Args>(m_tuple_args)...);
    }

    void func_tuple(Args... args) {}
};

int main(int argc, char** argv) {

    store_in_tuple<int, float, double, int> sit1(1, 2.0f, 3.0, 4);
    sit1.func(); // <- not ok

    store_in_tuple<int, float, double, size_t> sit2(1, 2.0f, 3.0, 4);
    sit2.func(); // <- ok

    return 0;
}

Why does this happen and is there a workaround ?


Solution

  • Use C++17 std::apply() to pass all the elements of a tuple to a function.

    std::apply([&](auto... x){ func_tuple(x...); }, m_tuple_args);
    

    You insist on staying with C++14?
    No problem, cppreference.com shows a short and simple production-quality example-implementation.

    Alternatively, you can work directly with std::make_index_sequence to get unique indices instead of duplicated types.