【问题标题】:Wrapping container for containers providing diffrent interfaces为提供不同接口的容器包装容器
【发布时间】:2017-03-29 20:27:30
【问题描述】:

我想为 stl 容器创建通用“包装器”,例如:

template<template <typename, typename...> class Container = std::vector >
class ContainerWrapper{
  add();
  size();
  find();
  resize();
  sort(); 
  /**/
}

+迭代器。 我希望成员函数具有不同的实现,具体取决于容器提供的方法。 C++ 模板系统是否足以创建这个?这甚至可能吗,只使用标准(没有提升,没有搞乱预处理器)?

我知道如何做到这一点——为每个 stl 容器编写模板特化。但我也希望它能够与其他容器一起使用,而且我正在寻找更通用的方法来做到这一点。

另外,这里有什么更好的地方?继承自 Container 还是将 Container 作为组件?

【问题讨论】:

  • 关于标准容器,它们不是为继承而设计的。
  • 因为每个ContainerWrapper 都是不相关的类型,你为什么要这个?我的意思是,不是每个标准容器都可以是resized。当通过std::set 时会发生什么,这如何使您的解决方案比首先使用std::set 更好?你沉迷于成为某种类型的成员吗?为什么不只是免费功能?喜欢sort(container)
  • @FrançoisAndrieux 作为我对答案的评论;它们的设计不是为了多态地继承

标签: c++ c++11 containers wrapper variadic-templates


【解决方案1】:

前段时间,我为我的一个项目开发了类似的东西。

我提取了一个完整的工作示例(原始代码更复杂)来展示如何使用方法addVal()(调用push_back()push()insert()push_front())来添加包装容器的值。

此代码适用于(如果我没记错的话)std::vectorstd::setstd::multisetstd::unordered_setstd::unordered_multisetstd::dequestd::queuestd::priority_queuestd::forward_list 和 @ 987654335@.

其他容器(例如std::array)可能需要cntWrp 的不同专业化。

我不想解释每一行代码,但是,如果您有任何问题,我可以尝试回复(或者,如果您愿意,我可以给您我的 github 项目的链接)。

例子

#include <set>
#include <vector>
#include <iostream>
#include <stdexcept>
#include <type_traits>

class emptyClass
 { };

template <typename ... Ts>
struct funcType;

template <typename T, typename ... Ts>
struct funcType<T, Ts...>
 { using type
      = typename std::conditional<T::result,
         typename T::type, typename funcType<Ts...>::type>::type; };

template <>
struct funcType<>
 { using type = emptyClass; };


#define methodCheck_1(meth)                            \
                                                       \
   class helpMeth_1_##meth {};                         \
                                                       \
   template <typename T, typename A>                   \
   struct isWithMethod_1_##meth                        \
    {                                                  \
      template<typename U>                             \
      static decltype(U().meth(A())) func (U*);        \
                                                       \
      template<typename U>                             \
      static emptyClass func (...);                    \
                                                       \
      static const bool result                         \
         = ! std::is_same<emptyClass,                  \
                decltype(func<T>(nullptr))>::value;    \
                                                       \
      using  type = helpMeth_1_##meth;                 \
    }

methodCheck_1(insert);
methodCheck_1(push);
methodCheck_1(push_back);
methodCheck_1(push_front);

template <typename>
class cntWrp;

template <template <typename ...> class C, typename X, typename ... Xs>
class cntWrp< C<X, Xs...> >
 {
   private:

      using addModeType = typename funcType<
         isWithMethod_1_push_back<C<X, Xs...>, X>,
         isWithMethod_1_insert<C<X, Xs...>, X>,
         isWithMethod_1_push<C<X, Xs...>, X>,
         isWithMethod_1_push_front<C<X, Xs...>, X>>::type;

      static constexpr addModeType  addMode {};

      void addVal (X const & x, helpMeth_1_push_back const)
       { val.push_back(x); }

      void addVal (X const & x, helpMeth_1_push const)
       { val.push(x); }

      void addVal (X const & x, helpMeth_1_insert const)
       { val.insert(x); }

      void addVal (X const & x, helpMeth_1_push_front const)
       { val.push_front(x); }

      void addVal (X const & x, emptyClass const)
       { throw std::runtime_error("cntWr<>::addVal without mode"); }

   public:

      C<X, Xs...> val {};

      cntWrp ()
       { }

      cntWrp (C<X, Xs...> const & v0) : val { v0 }
       { }

      void addVal (X const & x)
       { addVal(x, addMode); }
 };

int main ()
 {
   cntWrp<std::set<int>>  csi;

   csi.addVal(2);
   csi.addVal(7);
   csi.addVal(5);

   std::cout << "set:" << std::endl;

   for ( auto const elem : csi.val )
      std::cout << elem << std::endl;

   cntWrp<std::vector<int>> cvi;

   cvi.addVal(2);
   cvi.addVal(7);
   cvi.addVal(5);

   std::cout << "vector:" << std::endl;

   for ( auto const elem : cvi.val )
      std::cout << elem << std::endl;
 }

【讨论】:

    【解决方案2】:

    STL 容器不应该被继承。 They do not have virtual destructors。讨论了having the containers as final,但没有完成,因为它会发生重大变化。

    所以使用合成是你最好的选择。

    【讨论】:

    • 这不正确,您将继承和多态性混为一谈。 protectedpublic 的超集,因此非多态继承是使用 any 类的有效方式(除非它被标记为 final)。
    猜你喜欢
    • 2020-11-01
    • 2021-06-05
    • 1970-01-01
    • 2012-04-14
    • 2017-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多