转置结构容器

Transpose a container of structs

本文关键字:结构 转置      更新时间:2023-10-16

让我们有一个struct Record{uint8_t x, y;};,一个Container<Record>结构和一个struct Transposed{Container<uint8_t> x,y};的容器。容器c是一个模板,第一个参数是一种值类型,其余所有参数都有默认值。例如,它可以是std::vector(其余参数是类型(或std::span(其余参数是值(。模板应该适用于所有模板。此外,我们可能希望将模板参数的其余部分传递给底层模板。

如何使用模板从容器中获取Transposed

我尝试过可变参数模板,

#include <iostream>
#include <vector>
template <typename value_type=uint8_t> struct Record{
value_type x, y;
};
template<typename value_type, typename value_type2=uint8_t> class ContainerA: public std::vector<value_type>{
value_type2 b=1u;
};
template<typename value_type, uint8_t int_value=1u> class ContainerB: public std::vector<value_type>{};
template<typename value_type, template <typename ...> typename container_type> class Transposed{
container_type<value_type> x, y;
public:
Transposed(container_type<Record<value_type>> & recs){
x.reserve(recs.size());
y.reserve(recs.size());
x.resize(recs.size());
y.resize(recs.size());
size_t i=0;
for(auto &rec :recs){
x[i] = rec.x;
y[i] = rec.y;
++i;
}
}
};
int main(){
std::vector<Record<uint8_t>> recsV{
{1, 2},
{3, 4}
};
Transposed trV{recsV};
std::cout<<"vec"<<std::endl;
ContainerA<Record<uint8_t>> recsA{
{1, 2},
{3, 4}
};
Transposed trA{recsA};
std::cout<<"A"<<std::endl;
/*ContainerB<Record<uint8_t>> recsB{
{1, 2},
{3, 4}
};
Transposed trB{recsB};
std::cout<<"B"<<std::endl;*/
return 0;
}

但似乎它们无法同时匹配类型和值。不允许使用超过 1 个可变参数模板参数。这是C++语言中的缺陷还是故意的设计选择,我们是否需要像any_template_arg关键字这样的东西,或者应该只指定 2 个不同类型的可变参数来允许这个用例?

据我所知,没有办法将类型和值(以及模板模板(模板参数匹配在一起。我已经搜索了很长时间。

所以我看不出有什么方法可以用简单而优雅的方式制作你想要的东西。

尝试回答您的问题

如何使用模板从容器中获取Transposed

我能想象的最好的是声明(没有必要定义它们,它们只在decltype()内使用(几个琐碎的函数如下

template <typename VT,
template <typename...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
template <typename VT,
template <typename, auto...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);

第一个是当CT容器接受可变参数类型列表(std::vectorContainerA大小写(时删除Record部分;第二个是CT容器接受(在类型参数之后(一个或多个值(ContainerB大小写(。

显然,这并不能涵盖所有可能的情况,但是声明其他extract_func()函数以涵盖其他情况是微不足道的。

现在您可以按如下方式声明Tranposed

template <typename T,
typename CT = decltype(extract_func(std::declval<T>()))>
class Transposed

请注意,现在,Transposed接受泛型类型T但仅当T类型与extract_func()声明匹配(作为参数(时,才启用 SFINAE。

Transposed主体中,可以使用CT声明构造函数参数的xyT

以下是完整的编译示例

#include <iostream>
#include <vector>
template <typename value_type=std::uint8_t>
struct Record
{ value_type x, y; };
template <typename value_type, typename value_type2=std::uint8_t>
class ContainerA : public std::vector<value_type>
{ value_type2 b=1u; };
template <typename value_type, std::uint8_t int_value=1u>
class ContainerB : public std::vector<value_type>
{ };
template <typename VT,
template <typename...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
template <typename VT,
template <typename, auto...> typename CT>
CT<VT> extract_func (CT<Record<VT>>);
template <typename T,
typename CT = decltype(extract_func(std::declval<T>()))>
class Transposed
{
private:
CT x, y;
public:
Transposed (T & recs)
{
x.reserve(recs.size());
y.reserve(recs.size());
x.resize(recs.size());
y.resize(recs.size());
std::size_t i=0u;
for(auto &rec :recs){
x[i] = rec.x;
y[i] = rec.y;
++i;
}
}
};
int main ()
{
std::vector<Record<std::uint8_t>> recsV { {1, 2}, {3, 4} };
Transposed trV{recsV};
std::cout<<"vec"<<std::endl;
ContainerA<Record<std::uint8_t>> recsA { };
Transposed trA{recsA};
std::cout<<"A"<<std::endl;
ContainerB<Record<std::uint8_t>> recsB { };
Transposed trB{recsB};
std::cout<<"B"<<std::endl;
}

一个工作示例:

template<typename value_type=uint8_t>
struct Record{
value_type x, y;
};
template<class T>
std::vector<T> rebind_container(std::vector<Record<T>> const&);
// Span transposes into vector.
template<class T>
std::vector<T> rebind_container(std::span<Record<T>> const&); 
template<class T>
std::list<T> rebind_container(std::list<Record<T>> const&);
inline void reserve(...) {}
template<class... Args>
inline void reserve(std::vector<Args...>* v, size_t n) {
v->reserve(n);
}
template<class container_type>
struct Transposed {
using container_type2 = decltype(rebind_container(std::declval<container_type>()));
container_type2 x, y;
Transposed(container_type const& recs) {
auto const n = recs.size();
reserve(&x, n);
reserve(&y, n);
for(auto& rec : recs) {
x.push_back(rec.x);
y.push_back(rec.y);
}
}
};
int main(){
std::vector<Record<uint8_t>> recsV{
{1, 2},
{3, 4}
};
Transposed<decltype(recsV)> trV{recsV};
std::cout << trV.x.size() << std::endl;
std::list<Record<uint8_t>> recsV2{
{1, 2},
{3, 4}
};
Transposed<decltype(recsV2)> trV2{recsV2};
std::cout << trV2.x.size() << std::endl;
}