Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/140.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通用设计混合了奇怪的重复模板模式。C++;_C++_Oop_Templates_Design Patterns_Traits - Fatal编程技术网

C++ 通用设计混合了奇怪的重复模板模式。C++;

C++ 通用设计混合了奇怪的重复模板模式。C++;,c++,oop,templates,design-patterns,traits,C++,Oop,Templates,Design Patterns,Traits,考虑这类问题。我有一个Base类和三个派生自Base的类。例如:DerivedA、DerivedB和DerivedC。每个派生类都有其唯一的容器。因此DerivedA具有std::vector,DerivedB具有std::set和DerivedC具有std::map。我希望在Base中有一个接口来访问它当前指向的派生类的容器 Base* d1 = new DerivedA; for(std::vector<int>::iterator iter = d1->begin();

考虑这类问题。我有一个
Base
类和三个派生自
Base
的类。例如:
DerivedA
DerivedB
DerivedC
。每个派生类都有其唯一的容器。因此
DerivedA
具有
std::vector
DerivedB
具有
std::set
DerivedC
具有
std::map
。我希望在
Base
中有一个接口来访问它当前指向的派生类的容器

Base* d1 = new DerivedA;
for(std::vector<int>::iterator iter = d1->begin(); iter != d1->end(); ++iter)
{
     //processing
}

给我提个建议。我有点迷失在这个可怕的设计中。

为了做你想做的事情,你需要定义一个常见类型的迭代器,它可以从派生类中不同的
begin()
end()
重写返回

当然,在此之前,您需要决定您希望迭代器做什么,正如雅克在评论中解释的那样。对于初学者来说,您需要决定通过这样一个迭代器间接执行将产生什么
value\u type
。给定三个不同的容器,我能想到的唯一常见类型是
const int
,因为
std::map
s中的键是
const
std::set
迭代器是
const
迭代器(因为元素本身就是键)。因此,当使用公共迭代器类型进行迭代时,您只能观察其中的
int
s

现在,迭代器实现将需要调用不同的代码(在运行时),具体取决于它起源的派生类。这是类型擦除的典型用例。如果操作正确,这将允许您包装任何类型的迭代器,只要它支持您需要的接口。然而,在您的例子中,您可能不需要走那么远,因为我假设您知道需要支持的完整容器集,因此迭代器类型集也是众所周知的,并且也是有界的

这意味着您可以使用
boost::variant
来存储包装的迭代器。这应该比完整类型擦除解决方案更有效,因为它避免了一些内部虚拟函数调用和可能的堆分配(除非类型擦除解决方案可以使用某种小对象优化,这对于迭代器来说是相当可能的,但实现起来更复杂)

下面是这样一个迭代器的框架实现,以及使用它的类层次结构和一些简单的测试代码。注意,我只实现了使循环工作所需的基本迭代器功能

#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iterator>
#include "boost/variant.hpp"


//Helper function object types to implement each operator on the variant iterator.

struct indirection_visitor : boost::static_visitor<const int&>
{
   const int& operator()(std::vector<int>::iterator i) const { return *i; }
   const int& operator()(std::set<int>::iterator i) const { return *i; }
   const int& operator()(std::map<int, std::string>::iterator i) const { return i->first; }
};

struct prefix_increment_visitor : boost::static_visitor<>
{
   template<typename I> void operator()(I& i) const { ++i; }
};


//The iterator itself.
//It should probably hide the internal variant, in which case the non-member operators 
//should be declared as friends.

struct var_iterator : std::iterator<std::bidirectional_iterator_tag, const int>
{
   var_iterator() { }
   template<typename I> var_iterator(I i) : it(i) { }

   boost::variant<std::vector<int>::iterator, std::set<int>::iterator, std::map<int, std::string>::iterator> it;

   const int& operator*() { return boost::apply_visitor(indirection_visitor(), it); }

   var_iterator& operator++()
   {
      boost::apply_visitor(prefix_increment_visitor(), it);
      return *this;
   }
};

inline bool operator==(var_iterator i1, var_iterator i2) { return i1.it == i2.it; }
inline bool operator!=(var_iterator i1, var_iterator i2) { return !(i1 == i2); }


//Here's the class hierarchy.
//We use CRTP only to avoid copying and pasting the begin() and end() overrides for each derived class.

struct Base
{
   virtual var_iterator begin() = 0;
   virtual var_iterator end() = 0;
};

template<typename D> struct Base_container : Base
{
   var_iterator begin() override { return static_cast<D*>(this)->container.begin(); }
   var_iterator end() override { return static_cast<D*>(this)->container.end(); }
};

struct DerivedA : Base_container<DerivedA>
{
   std::vector<int> container;
};

struct DerivedB : Base_container<DerivedB>
{
   std::set<int> container;
};

struct DerivedC : Base_container<DerivedC>
{
   std::map<int, std::string> container;
};


//Quick test.

void f(Base* bp)
{
   for(auto iter = bp->begin(); iter != bp->end(); ++iter)
   {
      std::cout << *iter << ' ';
   }
   std::cout << '\n';

   //We have enough to make range-based for work too.
   for(auto i : *bp)
      std::cout << i << ' ';
   std::cout << '\n';
}

int main()
{
   DerivedA da;
   da.container = {1, 2, 3};
   f(&da);
   DerivedB db;
   db.container = {4, 5, 6};
   f(&db);
   DerivedC dc;
   dc.container = std::map<int, std::string>{{7, "seven"}, {8, "eight"}, {9, "nine"}};
   f(&dc);
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括“增压/变型.hpp”
//帮助函数对象类型,以实现变量迭代器上的每个运算符。
结构间接\u访问者:boost::static\u访问者
{
const int&operator()(std::vector::iterator i)const{return*i;}
const int&operator()(std::set::iterator i)const{return*i;}
const int&operator()(std::map::iterator i)const{return i->first;}
};
结构前缀\u增量\u访问者:boost::static\u访问者
{
模板void运算符()(I&I)常量{++I;}
};
//迭代器本身。
//它可能会隐藏内部变量,在这种情况下,非成员运算符
//应该被宣布为朋友。
结构变量迭代器:std::迭代器
{
var_迭代器(){}
模板变量迭代器(I):它(I){
促进:改变它;
常量int&运算符*(){return boost::apply_visitor(间接_visitor(),it);}
var_迭代器和运算符++()
{
boost::apply_visitor(前缀_increment_visitor(),it);
归还*这个;
}
};
内联布尔运算符==(var_迭代器i1,var_迭代器i2){return i1.it==i2.it;}
内联布尔运算符=(var_迭代器i1,var_迭代器i2){return!(i1==i2);}
//这是类的层次结构。
//我们使用CRTP只是为了避免复制和粘贴每个派生类的begin()和end()重写。
结构基
{
虚拟变量迭代器begin()=0;
虚拟变量迭代器end()=0;
};
模板结构基本容器:基本
{
var_迭代器begin()重写{return static_cast(this)->container.begin();}
var_迭代器end()重写{return static_cast(this)->container.end();}
};
struct DerivedA:Base\u容器
{
载体容器;
};
结构DerivedB:基本容器
{
std::set容器;
};
struct DerivedC:Base\u容器
{
映射容器;
};
//快速测试。
空f(基准*bp)
{
对于(自动iter=bp->begin();iter!=bp->end();++iter)
{

std::cout您需要什么访问容器的权限?开始迭代器和结束迭代器。这就足够了(我指的是迭代器)满足您的需要。但是您需要什么呢。在很少的情况下,您需要这些迭代器。您有一个问题。您想出了一个解决方案:但这个(对您来说很小)你不理解它的问题。你不理解它的事实意味着你不知道它有多大。备份:是什么问题促使你走这条路?你想迭代元素吗?迭代键吗?什么代码可以迭代int->string映射和一组int?
#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iterator>
#include "boost/variant.hpp"


//Helper function object types to implement each operator on the variant iterator.

struct indirection_visitor : boost::static_visitor<const int&>
{
   const int& operator()(std::vector<int>::iterator i) const { return *i; }
   const int& operator()(std::set<int>::iterator i) const { return *i; }
   const int& operator()(std::map<int, std::string>::iterator i) const { return i->first; }
};

struct prefix_increment_visitor : boost::static_visitor<>
{
   template<typename I> void operator()(I& i) const { ++i; }
};


//The iterator itself.
//It should probably hide the internal variant, in which case the non-member operators 
//should be declared as friends.

struct var_iterator : std::iterator<std::bidirectional_iterator_tag, const int>
{
   var_iterator() { }
   template<typename I> var_iterator(I i) : it(i) { }

   boost::variant<std::vector<int>::iterator, std::set<int>::iterator, std::map<int, std::string>::iterator> it;

   const int& operator*() { return boost::apply_visitor(indirection_visitor(), it); }

   var_iterator& operator++()
   {
      boost::apply_visitor(prefix_increment_visitor(), it);
      return *this;
   }
};

inline bool operator==(var_iterator i1, var_iterator i2) { return i1.it == i2.it; }
inline bool operator!=(var_iterator i1, var_iterator i2) { return !(i1 == i2); }


//Here's the class hierarchy.
//We use CRTP only to avoid copying and pasting the begin() and end() overrides for each derived class.

struct Base
{
   virtual var_iterator begin() = 0;
   virtual var_iterator end() = 0;
};

template<typename D> struct Base_container : Base
{
   var_iterator begin() override { return static_cast<D*>(this)->container.begin(); }
   var_iterator end() override { return static_cast<D*>(this)->container.end(); }
};

struct DerivedA : Base_container<DerivedA>
{
   std::vector<int> container;
};

struct DerivedB : Base_container<DerivedB>
{
   std::set<int> container;
};

struct DerivedC : Base_container<DerivedC>
{
   std::map<int, std::string> container;
};


//Quick test.

void f(Base* bp)
{
   for(auto iter = bp->begin(); iter != bp->end(); ++iter)
   {
      std::cout << *iter << ' ';
   }
   std::cout << '\n';

   //We have enough to make range-based for work too.
   for(auto i : *bp)
      std::cout << i << ' ';
   std::cout << '\n';
}

int main()
{
   DerivedA da;
   da.container = {1, 2, 3};
   f(&da);
   DerivedB db;
   db.container = {4, 5, 6};
   f(&db);
   DerivedC dc;
   dc.container = std::map<int, std::string>{{7, "seven"}, {8, "eight"}, {9, "nine"}};
   f(&dc);
}