我可以从向量数组初始化 std::tuple 吗?
can I initialize an std::tuple from a vector array?
我有一个 std::vector 包含变体 class。我想用相同的数据构造一个元组。这可能吗?元组的正常构造方法似乎非常严格。
//In reality, I'm using JUCE::var.
// SimpleVariant is here just to make the example code more explicit.
struct SimpleVariant
{
SimpleVariant(int i) : a(i), b("") {}
SimpleVariant(const std::string& s) : a(0), b(s) {}
operator int() const { return a; }
operator std::string() const { return b; }
private:
int a;
std::string b;
};
template <typename... T>
struct VariantTuple
{
VariantTuple(const std::vector<SimpleVariant>& v)
{
// how do I initialize the tuple here?
}
private:
std::tuple<T...> tuple;
};
std::vector<SimpleVariant> v{ SimpleVariant(1),
SimpleVariant(2),
SimpleVariant("a") };
VariantTuple<int, int, std::string> t (v);
根据评论的一些说明:
我不需要元组逐项匹配数组,或从给定数组推导类型。我想获取一个给定的数组,然后提取与特定类型匹配的变体。因此,例如,给定上面的数组 v
,我希望能够构造一个 VariantTuple<int, std::string>
,并让它匹配术语“1”和 "a"。这引入了许多超出我最初问题范围的其他问题。但我现在感兴趣的问题是是否有可能首先基于数组构造一个元组。
嗯,我不确定您是否要求动态推断向量元素的数量并构造元组,这是不可能的,但您可以开始了。我使用 std::index_sequence
根据 VariantTuple
的参数大小推导出元组元素的数量。这需要 C++17,因为它使用折叠表达式。
#include <initializer_list>
#include <string>
#include <vector>
#include <tuple>
#include <utility>
#include <type_traits>
#include <ostream>
#include <iostream>
struct SimpleVariant
{
SimpleVariant(int i) : a(i), b("") {}
SimpleVariant(const std::string& s) : a(0), b(s) {}
operator int() const {
return a;
}
operator std::string() const {
return b;
}
int a;
std::string b;
};
template<typename V, size_t... dim, typename... Args>
auto populate_tuple(const V& vec, std::index_sequence<dim...>, const std::tuple<Args...>& t) {
return std::make_tuple(static_cast<std::remove_reference_t<decltype(std::get<dim>(t))>>(vec.at(dim))...);
}
template<size_t... dim, typename... Args>
std::ostream& dump_tuple(std::ostream& out, const std::tuple<Args...>& tpl, std::index_sequence<dim...>) {
((out << std::get<dim>(tpl) << ","), ...);
return out;
}
template<typename... T>
struct VariantTuple
{
VariantTuple(const std::vector<SimpleVariant>& v) : tpl(populate_tuple(v, std::make_index_sequence<sizeof...(T)>{}, tpl)) {}
template<typename... V>
friend std::ostream& operator <<(std::ostream& out, const VariantTuple<V...>& vt) {
return dump_tuple(out, vt.tpl, std::make_index_sequence<sizeof...(V)>{});
}
private:
std::tuple<T...> tpl;
};
int main() {
std::vector<SimpleVariant> v {
SimpleVariant(1),
SimpleVariant(2),
SimpleVariant("a")
};
VariantTuple<int, int, std::string> t (v);
std::cout << t << std::endl;
return 0;
}
我有一个 std::vector 包含变体 class。我想用相同的数据构造一个元组。这可能吗?元组的正常构造方法似乎非常严格。
//In reality, I'm using JUCE::var.
// SimpleVariant is here just to make the example code more explicit.
struct SimpleVariant
{
SimpleVariant(int i) : a(i), b("") {}
SimpleVariant(const std::string& s) : a(0), b(s) {}
operator int() const { return a; }
operator std::string() const { return b; }
private:
int a;
std::string b;
};
template <typename... T>
struct VariantTuple
{
VariantTuple(const std::vector<SimpleVariant>& v)
{
// how do I initialize the tuple here?
}
private:
std::tuple<T...> tuple;
};
std::vector<SimpleVariant> v{ SimpleVariant(1),
SimpleVariant(2),
SimpleVariant("a") };
VariantTuple<int, int, std::string> t (v);
根据评论的一些说明:
我不需要元组逐项匹配数组,或从给定数组推导类型。我想获取一个给定的数组,然后提取与特定类型匹配的变体。因此,例如,给定上面的数组 v
,我希望能够构造一个 VariantTuple<int, std::string>
,并让它匹配术语“1”和 "a"。这引入了许多超出我最初问题范围的其他问题。但我现在感兴趣的问题是是否有可能首先基于数组构造一个元组。
嗯,我不确定您是否要求动态推断向量元素的数量并构造元组,这是不可能的,但您可以开始了。我使用 std::index_sequence
根据 VariantTuple
的参数大小推导出元组元素的数量。这需要 C++17,因为它使用折叠表达式。
#include <initializer_list>
#include <string>
#include <vector>
#include <tuple>
#include <utility>
#include <type_traits>
#include <ostream>
#include <iostream>
struct SimpleVariant
{
SimpleVariant(int i) : a(i), b("") {}
SimpleVariant(const std::string& s) : a(0), b(s) {}
operator int() const {
return a;
}
operator std::string() const {
return b;
}
int a;
std::string b;
};
template<typename V, size_t... dim, typename... Args>
auto populate_tuple(const V& vec, std::index_sequence<dim...>, const std::tuple<Args...>& t) {
return std::make_tuple(static_cast<std::remove_reference_t<decltype(std::get<dim>(t))>>(vec.at(dim))...);
}
template<size_t... dim, typename... Args>
std::ostream& dump_tuple(std::ostream& out, const std::tuple<Args...>& tpl, std::index_sequence<dim...>) {
((out << std::get<dim>(tpl) << ","), ...);
return out;
}
template<typename... T>
struct VariantTuple
{
VariantTuple(const std::vector<SimpleVariant>& v) : tpl(populate_tuple(v, std::make_index_sequence<sizeof...(T)>{}, tpl)) {}
template<typename... V>
friend std::ostream& operator <<(std::ostream& out, const VariantTuple<V...>& vt) {
return dump_tuple(out, vt.tpl, std::make_index_sequence<sizeof...(V)>{});
}
private:
std::tuple<T...> tpl;
};
int main() {
std::vector<SimpleVariant> v {
SimpleVariant(1),
SimpleVariant(2),
SimpleVariant("a")
};
VariantTuple<int, int, std::string> t (v);
std::cout << t << std::endl;
return 0;
}