Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/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++_Templates_Std - Fatal编程技术网

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