C++ 使用模板来克服基类的不足?
显然,标准容器没有公共基类,也没有公共接口,尽管方法名是同构的 问题是:我必须用一组独特类型的对象来填充容器。该容器可以是C++ 使用模板来克服基类的不足?,c++,templates,std,C++,Templates,Std,显然,标准容器没有公共基类,也没有公共接口,尽管方法名是同构的 问题是:我必须用一组独特类型的对象来填充容器。该容器可以是std::list、std::vector或std::deque,也可能是其他一些自定义容器。以下代码是最佳解决方案吗 # include <string> # include <iostream> # include <list> # include <vector> # include <deque> /*
std::list
、std::vector
或std::deque
,也可能是其他一些自定义容器。以下代码是最佳解决方案吗
# include <string>
# include <iostream>
# include <list>
# include <vector>
# include <deque>
/*
* Fill a container with two strings. The container
* must expose the `clear` and `push_back` methods.
*/
template<typename T>
void f(T & t)
{
t.clear() ;
t.push_back("Alice") ;
t.push_back("Bob") ;
}
int main(int, char*[])
{
std::list<std::string> l ;
std::vector<std::string> v ;
std::deque<std::string> q ;
f(l) ; // fill the list
f(v) ; // fill the vector
f(q) ; // fill the double-ended queue
// possibly anything with `clear` and `push_back` methods
// can be filled with `f`
return 0 ;
}
我正在寻找一种更好的方法来声明GetSupportedFormats
,这样它就可以处理许多其他容器,而不仅仅是std::list
s。这就是我第一篇文章的要点。我最喜欢的是:
/*
* Fill a container with two strings. The container
* must expose the `clear` and `push_back` methods.
*/
template<typename T>
void f(T & t)
{
t.clear() ;
std::insert_iterator<T> it(t, t.end());
*it++ = "Alice";
*it++ = "Bob";
}
/*
*用两根绳子装满一个容器。容器
*必须公开'clear'和'push_back'方法。
*/
模板
空f(T&T)
{
t、 清除();
std::insert_迭代器it(t,t.end());
*it++=“爱丽丝”;
*it++=“鲍勃”;
}
现在的约束是:clear
和insert
,因此它也可以用于std::set
。此外,它可以与任何类型一起工作,您只需专门为它设计std::insert_迭代器模板。这是一种解决方案
更“STL”风格的解决方案是使用
charconst*names[2]={“Alice”,“Bob”};
std::列表l;
std::向量v;
标准:德克q;
std::copy(名称,名称+2,std::back_插入器(l));
std::copy(名称,名称+2,std::back_插入器(v));
std::copy(名称,名称+2,std::back_插入器(q));
使用clear()和add()方法提供您自己的抽象类
然后你就可以从中得到
template <typename Container>
class TemplatedContainer : public ContainerIntarface {
virtual void clear() {c_.clear();}
virtual void add(const UniqueType &e) {std::inserter(c_, c_.end()) = e;}
private:
Container c_;
};
模板
类TemplatedContainer:公共容器TarFace{
虚空清除()
虚拟void add(const UniqueType&e){std::inserter(c_,c_.end())=e;}
私人:
集装箱c_2;;
};
这假设您只有一种类型要存储在容器中。如果不是这样,您的基类也会变成一个temaplate,派生类需要一个模板参数,它是一个模板(std::vector
,而不是std::vector
)也许我不理解您的问题。选择list、vector或deque取决于您需要对对象执行的操作。没有一个比其他的更好。@Carey Gregory:这就是为什么我希望f
有点“通用”:它可以处理list
,vector
,deque
。。。根据情况和我的选择。@overcoder——泛型算法使用迭代器,而不是值。你的通用性是有限的,这就是为什么有不同类别的迭代器的原因,你不能一刀切。@Gene:通用算法最好使用范围(哪些容器是范围)。@Gene:即使允许
中的算法使用迭代器,它们不是世界上唯一的算法,也不是唯一的通用代码。编写直接作用于容器的泛型代码并没有什么特别错误,因为有些常见操作(如擦除-删除习惯用法,或者在本例中为清空)绝对需要使用容器。只能使用迭代器实现的操作应该是(如果你遵循标准的库习惯用法,也就是说),这是一个不能实现的操作。@GMan:你能为直接使用迭代器的f
提出一个实现方案吗?@overcoder:只需在这个答案中保留代码,但要使顶部的模板无效f(OutIter it)
,然后这样称呼它,例如:f(std::back\u inserter(v))
@GMan:记住我们需要先clear()
,所以f
必须使用容器和迭代器。@Steve:我不同意。(我是说,你说得对,但设计应该改变)。如果要附加到现有数据,该怎么办?为什么我要在函数中清除?如果我想清除容器,我会在调用该函数之前执行该操作。@GMan:如果愿意,您可以播放猫的有趣视频,但在这个问题中,请求的是一个通用函数,该函数清除容器,然后在其中放入两个字符串。如果不想编写该函数,请继续运行;-)诚然,编写一个只执行插入操作的函数g
可能是值得的,因为这是一个可以明确识别的子任务,但仍有f
需要编写。@Arkadly:谢谢!我会调查你的提议。我看不出containerface
给聚会带来了什么。泛型代码在并没有公共基类的情况下运行得很好,事实上这就是关键所在。@Steve Jessop:它带来了运行时多态性。OP在他最初的示例中不需要它,但在将来某个时候可能需要它。也许ContainerInterface使您可以在所有代码中不使用模板。正常功能也将起作用:void f(容器接口&c)@彼得·亚历山大:太好了,如果将来需要的话,我可以在将来添加它-P
char const* names[2] = { "Alice", "Bob" };
std::list<std::string> l;
std::vector<std::string> v;
std::deque<std::string> q;
std::copy(names, names+2, std::back_inserter(l));
std::copy(names, names+2, std::back_inserter(v));
std::copy(names, names+2, std::back_inserter(q));
class ContainerIterface
{
public:
virtual void clear() = 0;
virtual void add(const UniqueType &e) = 0;
};
template <typename Container>
class TemplatedContainer : public ContainerIntarface {
virtual void clear() {c_.clear();}
virtual void add(const UniqueType &e) {std::inserter(c_, c_.end()) = e;}
private:
Container c_;
};