让我们有一个struct Record{uint8_t x, y;};
,一个结构容器Container<Record>
和一个struct Transposed{Container<uint8_t> x,y};
。容器c
是一个模板,其第一个arg是值的类型,其余所有args均具有默认值。例如,它可以是std::vector
(其余arg是类型)或std::span
(其余arg是值)。该模板应适用于所有这些模板。另外,我们可能希望将其余模板参数传递给基础模板。
我们如何使用模板从容器中获取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个不同类型的可变参数才能使用此用例?
答案 0 :(得分:1)
据我所知,还没有一种将类型和值(以及模板模板)模板参数匹配在一起的方法。我已经搜索了很长时间。
因此,我没有找到一种简单而优雅的方式来制作想要的东西的方法。
尝试回答您的问题
我们如何使用模板从容器中获取
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>>);
第一个是当Record
容器接受可变的类型列表(CT
和std::vector
情况下,删除ContainerA
部分;第二个用于CT
容器(在type参数之后)接受一个或多个值(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
声明x
以及y
和T
作为构造函数的参数。
以下是完整的编译示例
#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;
}
答案 1 :(得分:0)
一个适合您的示例:
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;
}