当前位置: 首页 > 知识库问答 >
问题:

转置结构的容器

秦滨海
2023-03-14

让我们有一个结构记录{uint8_t x,y;} ,一个容器容器

如何使用模板从容器中获取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;
}

但它们似乎无法同时匹配类型和值。不允许使用多个可变模板参数。这是C语言中的一个缺陷还是故意的设计选择?我们是否需要类似于any\u template\u arg关键字之类的东西,还是应该只指定两个不同类型的可变参数就可以允许这个用例?


共有2个答案

华建同
2023-03-14

您可以举一个工作示例:

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;
}
齐高阳
2023-03-14

据我所知,没有一种方法可以将类型和值(以及模板)模板参数匹配在一起。我已经找了很久了。

所以我看不到一种简单优雅的方式来制作你想要的东西。

试着回答你的问题

如何使用模板从容器中获取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::向量ContainerA大小写)时删除记录部分;第二个是用于容器CT接受(在类型参数之后)一个或多个值(ContainerBcase)。

显然,这并没有涵盖所有可能的情况,但声明其他extract_func()函数来涵盖其他情况并不重要。

现在,您可以如下声明transposed

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;
 }

 类似资料:
  • 3.2.1 配置结构 当默认的工程结构不适用的时候,你可能需要配置它。根据 Gradle 文档说明,可以通过如下方式重新配置Java工程的 sourceSets: sourceSets { main { java { srcDir 'src/java' } resources { srcDir

  • 当默认的项目结构不适用时,可以自定义配置。查看 Gradle 文档中 Java plugin 部分以了解如何在纯 Java 项目中进行配置。 Android plugin 使用了类似的语法,但因为 Android 有自己的 sourceSets,所以需要配置到 android 块中。下面的例子使用了旧的项目结构(Eclipse),并把 androidTest 的 sourceSet 映射到 tes

  • 本部分讨论三个库:Boost.Any, Boost.Variant, 和 Boost.Tuple. 在某种意义上,它们都是容器,虽然它们与标准库的容器类毫无共同之处。它们都是非常有用的库,许多人和我一样,每天都在使用它们来解决编程上的问题。它们 所解决的问题是C++或C++标准库所未能覆盖的范畴,因此它们确实是我们的库工具箱的非常重要的扩展。想一下基础数据结构的有效性将影响我们编程及设计 的方法,

  • 这是我关于Stackoverflow的第一个问题,所以如果你在我的第一个帖子中发现任何荒谬的东西,请耐心等待。我已经看过SO FAQ了,我知道它的各种政策。您知道,我是一个大量使用PHP、Perl、Python、ROR等语言的人,最近我“上下文切换”到Java EE。您知道,我研究过的几种语言都有一个构造,使我能够递归地转储聚合结构的内容,而不需要for/foreach/for.in循环 例如,

  • 扁平数组的结构如上,每个目录下都可以添加数据 如何将这个数组转成树形的结构啊,转成如下的形式 目录层级的name就取对应的 xxxLevelStr

  • 谁能给我解释一下这个吗?