我将可变参数存储到std::tuple
内的对象构造函数中,到目前为止效果很好。但是,当使用存储的参数和std::get<>()
调用对象函数时,将抛出我根本不理解的 compile-time 断言失败。 仅当所有参数的类型都不相同时,才会发生这种情况。
编译器错误消息是:
msvc \ 14.16.27023 \ include \ tuple(934):错误C2338:重复类型T在 get(元组)
下面的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;
}
为什么会发生这种情况,并且有解决方法?
答案 0 :(得分:3)
该示例可以简化为以下内容:
auto t = std::make_tuple(1, 's', 2);
std::get<int>(t);
在这里,我们有一个t
类型的std::tuple<int, char, int>
。 std::get
也可以使用类型(以及索引),除非您有重复的类型。 std::get<char>
将起作用,因为char
中只有一个t
,但是std::get<int>
将不起作用,因为它不知道哪个 {{ 1}}来获取-int
或1
?
这是这里正在发生的事情:
2
void func() {
func_tuple(std::get<Args>(m_tuple_args)...);
}
扩展后,如果std::get<Args>
包含至少一种重复类型,则将不起作用,因为它只会不知道要提取哪个 < / em>。
答案 1 :(得分:2)
使用C++17 std::apply()
将元组的所有元素传递给函数。
import { addActiveDiv } from "foobar";
addActiveDiv(2000);
您坚持要坚持使用C ++ 14吗?
没问题,cppreference.com展示了一个简短而简单的生产质量示例实现。
或者,您可以直接与std::make_index_sequence
合作以获取唯一索引而不是重复的类型。
答案 2 :(得分:1)
为什么会发生[?]
当Args...
类型完全不同时,一切都会很好。
类型冲突时会出错。
这是因为std::get<T>(tuple_val)
,其中T
是一种类型,“除非元组恰好具有该类型的一个元素,否则编译失败”(您可以在this page中阅读)。在我看来,这是合理的。
所以一切顺利
store_in_tuple<int, float, double, size_t>
因为所有类型都不同,所以您会从中得到错误
store_in_tuple<int, float, double, int>
因为对std::get<int>(m_tuple_args)
的两次调用失败。
有解决方法吗?
使用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
。