std::tuple get<T>(tuple) 中的重复类型 T - 编译时断言失败
std::tuple duplicate type T in get<T>(tuple) - Compile time assertion failure
我正在将可变参数存储到 std::tuple
中的对象构造函数,到目前为止一切顺利。但是当使用存储的参数和 std::get<>()
调用对象函数时,我将抛出一个 compile-time 断言失败,我根本不明白。只有当所有参数都不是不同类型时才会发生这种情况。
编译器错误信息为:
msvc.16.27023\include\tuple(934): error C2338: duplicate type T in
get(tuple)
mcve 如下:
#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;
}
为什么会发生这种情况,是否有解决方法?
例子可以简化为:
auto t = std::make_tuple(1, 's', 2);
std::get<int>(t);
在这里,我们有一个 t
类型的 std::tuple<int, char, int>
。 std::get
也可以与类型一起使用(与索引一起),除非您有重复的类型。 std::get<char>
会工作,因为 t
中只有一个 char
,但是 std::get<int>
不会工作,因为它不知道 哪个 ] int
获取 - 1
或 2
?
这就是这里发生的事情:
void func() {
func_tuple(std::get<Args>(m_tuple_args)...);
}
扩展后的 std::get<Args>
如果 Args...
包含至少一个重复类型,则将不起作用,因为它 不知道 哪个 一个要取.
使用C++17 std::apply()
将元组的所有元素传递给函数。
std::apply([&](auto... x){ func_tuple(x...); }, m_tuple_args);
您坚持使用 C++14 吗?
没问题,cppreference.com 显示一个简短的 production-quality example-implementation.
或者,您可以直接使用 std::make_index_sequence
来获取唯一索引而不是重复类型。
Why does this happen [?]
当 Args...
类型完全不同时一切顺利。
类型冲突时会出现错误。
这是因为 std::get<T>(tuple_val)
,其中 T
是一种类型,"Fails to compile unless the tuple has exactly one element of that type"(您可以在 this page 中阅读)。这对我来说似乎很合理。
所以一切顺利
store_in_tuple<int, float, double, size_t>
因为所有的类型都不同,你从
得到一个错误
store_in_tuple<int, float, double, int>
因为对std::get<int>(m_tuple_args)
的两次调用都失败了。
and is there a workaround ?
使用 std::get()
的数字版本,它永远可用,当类型冲突时也是如此。
C++14 中的常用方法是通过带有 std::index_sequence
和 std::make_index_sequence
(或 std::index_sequence_for
)的辅助函数。
看似复杂其实很简单
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...>{}); }
如果你可以使用 C++17,你可以使用 std::apply()
,(我想)在幕后使用 std::index_sequence
。
我正在将可变参数存储到 std::tuple
中的对象构造函数,到目前为止一切顺利。但是当使用存储的参数和 std::get<>()
调用对象函数时,我将抛出一个 compile-time 断言失败,我根本不明白。只有当所有参数都不是不同类型时才会发生这种情况。
编译器错误信息为:
msvc.16.27023\include\tuple(934): error C2338: duplicate type T in get(tuple)
mcve 如下:
#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;
}
为什么会发生这种情况,是否有解决方法?
例子可以简化为:
auto t = std::make_tuple(1, 's', 2);
std::get<int>(t);
在这里,我们有一个 t
类型的 std::tuple<int, char, int>
。 std::get
也可以与类型一起使用(与索引一起),除非您有重复的类型。 std::get<char>
会工作,因为 t
中只有一个 char
,但是 std::get<int>
不会工作,因为它不知道 哪个 ] int
获取 - 1
或 2
?
这就是这里发生的事情:
void func() {
func_tuple(std::get<Args>(m_tuple_args)...);
}
扩展后的 std::get<Args>
如果 Args...
包含至少一个重复类型,则将不起作用,因为它 不知道 哪个 一个要取.
使用C++17 std::apply()
将元组的所有元素传递给函数。
std::apply([&](auto... x){ func_tuple(x...); }, m_tuple_args);
您坚持使用 C++14 吗?
没问题,cppreference.com 显示一个简短的 production-quality example-implementation.
或者,您可以直接使用 std::make_index_sequence
来获取唯一索引而不是重复类型。
Why does this happen [?]
当 Args...
类型完全不同时一切顺利。
类型冲突时会出现错误。
这是因为 std::get<T>(tuple_val)
,其中 T
是一种类型,"Fails to compile unless the tuple has exactly one element of that type"(您可以在 this page 中阅读)。这对我来说似乎很合理。
所以一切顺利
store_in_tuple<int, float, double, size_t>
因为所有的类型都不同,你从
得到一个错误store_in_tuple<int, float, double, int>
因为对std::get<int>(m_tuple_args)
的两次调用都失败了。
and is there a workaround ?
使用 std::get()
的数字版本,它永远可用,当类型冲突时也是如此。
C++14 中的常用方法是通过带有 std::index_sequence
和 std::make_index_sequence
(或 std::index_sequence_for
)的辅助函数。
看似复杂其实很简单
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...>{}); }
如果你可以使用 C++17,你可以使用 std::apply()
,(我想)在幕后使用 std::index_sequence
。