Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
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 ?
here, we have a t
of a type std::tuple<int, char, int>
. std::get
can also work with types (alongside indexes), unless you have a duplicate type. std::get<char>
will work since there is only one char
in the t
, but std::get<int>
will not work, since it does not know which int
to fetch - the 1
or the 2
?
This is what's happening here:
void func() {
func_tuple(std::get<Args>(m_tuple_args)...);
the std::get<Args>
, after expansion, will not work if Args...
contain at least one duplicate type, because it will simply not know which one to fetch.
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.
–
All goes well when the Args...
types are all differents.
You get an error when types collides.
This is because std::get<T>(tuple_val)
, where T
is a type, "Fails to compile unless the tuple has exactly one element of that type" (as you can read in this page). And this seems reasonable to me.
So all goes well with
store_in_tuple<int, float, double, size_t>
because all types are differents, and you get an error from
store_in_tuple<int, float, double, int>
because the two calls to std::get<int>(m_tuple_args)
fail.
and is there a workaround ?
Use the numeric version of std::get()
, that is ever available, also when types collides.
The usual way in C++14 pass through an helper function with std::index_sequence
and std::make_index_sequence
(or std::index_sequence_for
).
Seems complicated but it's very simple
template <std::size_t ... Is>
void func_helper (std::index_sequence<Is...> const)
{ func_tuple(std::get<Is>(m_tuple_args)...); }
void func ()
{ func_helper(std::index_sequence_for<Args...>{}); }
If you can use C++17, you can use std::apply()
that (I suppose) use std::index_sequence
under the hood.
–
–
–
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.