使用 tuple_cat 将参数包扩展为元组
Expand parameter pack into tuple with tuple_cat
神箭link: https://godbolt.org/z/18nseEn4G
我有一个 std::map 各种类型的向量(转换为 void*)和一个 T& get<T>
方法,它给我一个对地图中一个向量中的元素的引用。
class Container {
public:
Container() {
auto v1 = new std::vector<int>({1, 2, 3, 4, 5});
auto v2 = new std::vector<char>({'a','b','c','d','e'});
auto v3 = new std::vector<double>({1.12, 2.34, 3.134, 4.51, 5.101});
items.insert({
std::type_index(typeid(std::vector<int>)),
reinterpret_cast<void*>(v1)
});
items.insert({
std::type_index(typeid(std::vector<char>)),
reinterpret_cast<void*>(v2)
});
items.insert({
std::type_index(typeid(std::vector<double>)),
reinterpret_cast<void*>(v3)
});
}
template<typename T>
T& get(int index) {
auto idx = std::type_index(typeid(std::vector<T>));
auto ptr = items.at(idx);
auto vec = reinterpret_cast<std::vector<T>*>(ptr);
return (*vec)[index];
}
private:
std::map<std::type_index, void*> items {};
};
我希望能够使用结构化绑定取回对同一索引但在不同向量中的 3 个元素的引用,但我不确定如何通过多次调用 T& get<T>
方法。
像这样;
auto [a, b, c] = myContainer.get_all<int, char, double>(1); // get a reference to an int, a char, and a double from myContainer at index 1.
我目前正在尝试对参数包中的每个参数重复调用 T& get<T>
,但我无法找出正确的语法。
template<typename... Ts>
auto get_all(int index) {
return std::tuple_cat<Ts...>(
std::make_tuple<Ts>(get<Ts>(index)...)
);
我怎样才能完成这项工作?
这是我当前尝试的 link:
https://godbolt.org/z/18nseEn4G
或者,是否有“更好的方法”来实现这一目标?
简单地说:
template<typename... Ts>
auto get_all(int index) {
return std::tuple<Ts&...>(get<Ts>(index)...);
}
您可以使用 std::tie
将 get<Ts>(index)
中的所有“returns”打包成一个引用元组。看起来像
template<typename... Ts>
auto get_all(int index) {
return std::tie(get<Ts>(index)...);
}
我建议使用类型擦除。这是一个例子:
#include <vector>
#include <typeindex>
#include <memory>
#include <any>
#include <unordered_map>
#include <iostream>
#include <experimental/propagate_const>
// If no library implementation is availble, one may be copied from libstdc++
template<class T>
using propagate_const = std::experimental::propagate_const<T>;
class Container
{
public:
Container() {
std::unique_ptr<Eraser> v1{ static_cast<Eraser*>(new ErasedVector<int>(1, 2, 3, 4, 5)) };
std::unique_ptr<Eraser> v2{ static_cast<Eraser*>(new ErasedVector<char>('a','b','c','d','e')) };
std::unique_ptr<Eraser> v3{ static_cast<Eraser*>(new ErasedVector<double>(1.12, 2.34, 3.134, 4.51, 5.101)) };
items[std::type_index(typeid(int))] = std::move(v1);
items[std::type_index(typeid(char))] = std::move(v2);
items[std::type_index(typeid(double))] = std::move(v3);
}
template<typename... Ts>
std::tuple<Ts&...> get(size_t index)
{
return {
std::any_cast<std::reference_wrapper<Ts>>((*items.find(std::type_index{typeid(Ts)})->second)[index]).get()...
};
}
template<typename... Ts, typename = std::enable_if_t<(std::is_const_v<Ts> && ...)>>
std::tuple<Ts&...> get(size_t index) const
{
return {
std::any_cast<std::reference_wrapper<Ts>>((*items.find(std::type_index{typeid(Ts)})->second)[index]).get()...
};
}
private:
class Eraser
{
public:
virtual std::any operator[](size_t index) = 0;
virtual std::any operator[](size_t index) const = 0;
virtual ~Eraser() = default;
};
template <typename T>
class ErasedVector : public Eraser
{
public:
template <typename... Args>
ErasedVector(Args&&... args) :
data{ std::forward<Args>(args)... }
{
}
virtual std::any operator[](size_t index) override final
{
return std::reference_wrapper{ data[index] };
};
virtual std::any operator[](size_t index) const override final
{
return std::reference_wrapper{ data[index] };
}
private:
std::vector<T> data;
};
std::unordered_map<std::type_index, propagate_const<std::unique_ptr<Eraser>>> items;
};
在这个例子中它工作正常:
int main()
{
Container co;
auto [i0_0, c0_0, d0_0] = co.get<int, char, double>(0);
std::cout << i0_0 << ' ' << c0_0 << ' ' << d0_0 << '\n';
i0_0 = 3; // is a reference
d0_0 = 42; // is a reference
auto [i0_1, d0_1] = static_cast<const Container&>(co).get<const int, const double>(0); // works on const Container
std::cout << i0_1 << ' ' << d0_1; // original values modified
// i0_1 = 0xDEADBEEF; can be const too
}
并输出:
1 a 1.12
3 42
神箭link: https://godbolt.org/z/18nseEn4G
我有一个 std::map 各种类型的向量(转换为 void*)和一个 T& get<T>
方法,它给我一个对地图中一个向量中的元素的引用。
class Container {
public:
Container() {
auto v1 = new std::vector<int>({1, 2, 3, 4, 5});
auto v2 = new std::vector<char>({'a','b','c','d','e'});
auto v3 = new std::vector<double>({1.12, 2.34, 3.134, 4.51, 5.101});
items.insert({
std::type_index(typeid(std::vector<int>)),
reinterpret_cast<void*>(v1)
});
items.insert({
std::type_index(typeid(std::vector<char>)),
reinterpret_cast<void*>(v2)
});
items.insert({
std::type_index(typeid(std::vector<double>)),
reinterpret_cast<void*>(v3)
});
}
template<typename T>
T& get(int index) {
auto idx = std::type_index(typeid(std::vector<T>));
auto ptr = items.at(idx);
auto vec = reinterpret_cast<std::vector<T>*>(ptr);
return (*vec)[index];
}
private:
std::map<std::type_index, void*> items {};
};
我希望能够使用结构化绑定取回对同一索引但在不同向量中的 3 个元素的引用,但我不确定如何通过多次调用 T& get<T>
方法。
像这样;
auto [a, b, c] = myContainer.get_all<int, char, double>(1); // get a reference to an int, a char, and a double from myContainer at index 1.
我目前正在尝试对参数包中的每个参数重复调用 T& get<T>
,但我无法找出正确的语法。
template<typename... Ts>
auto get_all(int index) {
return std::tuple_cat<Ts...>(
std::make_tuple<Ts>(get<Ts>(index)...)
);
我怎样才能完成这项工作? 这是我当前尝试的 link: https://godbolt.org/z/18nseEn4G
或者,是否有“更好的方法”来实现这一目标?
简单地说:
template<typename... Ts>
auto get_all(int index) {
return std::tuple<Ts&...>(get<Ts>(index)...);
}
您可以使用 std::tie
将 get<Ts>(index)
中的所有“returns”打包成一个引用元组。看起来像
template<typename... Ts>
auto get_all(int index) {
return std::tie(get<Ts>(index)...);
}
我建议使用类型擦除。这是一个例子:
#include <vector>
#include <typeindex>
#include <memory>
#include <any>
#include <unordered_map>
#include <iostream>
#include <experimental/propagate_const>
// If no library implementation is availble, one may be copied from libstdc++
template<class T>
using propagate_const = std::experimental::propagate_const<T>;
class Container
{
public:
Container() {
std::unique_ptr<Eraser> v1{ static_cast<Eraser*>(new ErasedVector<int>(1, 2, 3, 4, 5)) };
std::unique_ptr<Eraser> v2{ static_cast<Eraser*>(new ErasedVector<char>('a','b','c','d','e')) };
std::unique_ptr<Eraser> v3{ static_cast<Eraser*>(new ErasedVector<double>(1.12, 2.34, 3.134, 4.51, 5.101)) };
items[std::type_index(typeid(int))] = std::move(v1);
items[std::type_index(typeid(char))] = std::move(v2);
items[std::type_index(typeid(double))] = std::move(v3);
}
template<typename... Ts>
std::tuple<Ts&...> get(size_t index)
{
return {
std::any_cast<std::reference_wrapper<Ts>>((*items.find(std::type_index{typeid(Ts)})->second)[index]).get()...
};
}
template<typename... Ts, typename = std::enable_if_t<(std::is_const_v<Ts> && ...)>>
std::tuple<Ts&...> get(size_t index) const
{
return {
std::any_cast<std::reference_wrapper<Ts>>((*items.find(std::type_index{typeid(Ts)})->second)[index]).get()...
};
}
private:
class Eraser
{
public:
virtual std::any operator[](size_t index) = 0;
virtual std::any operator[](size_t index) const = 0;
virtual ~Eraser() = default;
};
template <typename T>
class ErasedVector : public Eraser
{
public:
template <typename... Args>
ErasedVector(Args&&... args) :
data{ std::forward<Args>(args)... }
{
}
virtual std::any operator[](size_t index) override final
{
return std::reference_wrapper{ data[index] };
};
virtual std::any operator[](size_t index) const override final
{
return std::reference_wrapper{ data[index] };
}
private:
std::vector<T> data;
};
std::unordered_map<std::type_index, propagate_const<std::unique_ptr<Eraser>>> items;
};
在这个例子中它工作正常:
int main()
{
Container co;
auto [i0_0, c0_0, d0_0] = co.get<int, char, double>(0);
std::cout << i0_0 << ' ' << c0_0 << ' ' << d0_0 << '\n';
i0_0 = 3; // is a reference
d0_0 = 42; // is a reference
auto [i0_1, d0_1] = static_cast<const Container&>(co).get<const int, const double>(0); // works on const Container
std::cout << i0_1 << ' ' << d0_1; // original values modified
// i0_1 = 0xDEADBEEF; can be const too
}
并输出:
1 a 1.12
3 42