将std :: vector <t>函数应用于从std :: vector </t>派生的类

时间:2013-11-29 02:02:11

标签: c++ templates inheritance stdvector

如果一个类派生自一个向量,你怎么能在它上预先形成(模板化)向量函数?

例如,以下代码将无法编译:

#include <iostream>
#include <vector>
using namespace std;

class Batch:public vector<int>{};

template<class T>
vector<vector<T> > interleave(vector<T> v, unsigned l){
    vector<vector<T> > r(l);
    int i=0;
    for(const  &t:v) r[(i++)%l].push_back(t);
    return r;
}

template<class T>
vector<T> flatten(vector< vector<T> > w){
    vector<T> r;
    for(const vector<T> &v:w)
        r.insert(r.end(),v.begin(),v.end());
    return r;
}

int main(){
    Batch         a = {0,1,2,3,4,5,6,7,8,9,10,11};
    vector<Batch> b = interleave(a,3);
    Batch         c = flatten(b);
    for(auto d:c) cout<<d<<' ';
    cout<<endl;
}

但如果将class Batch:public vector<int>{};更改为typedef vector<int> Batch;以生成所需的输出,则会进行编译:{{1​​}}

2 个答案:

答案 0 :(得分:2)

函数重载决策将参数类类型映射到它专门化的模板,或映射到基类,但不映射到基类专用的模板。

你可以通过使用SFINAE来创建一个兼具两者功能的功能,虽然它有点棘手。我将在C ++ 11中执行此操作,但它本身并不需要任何新的语言功能。

template< template< typename ... > class a, template< typename ... > class b >
struct is_same_template : std::false_type {};

template< template< typename ... > class a >
struct is_same_template< a, a > : std::true_type {};

template< typename t >
typename std::enable_if< is_same_template< t::template vector, std::vector >::value,
    std::vector< t > >::type
interleave( t const & v, unsigned l ) {

不是查找继承本身,而是检查类是否与vector相同的成员模板std::vector。由于(目前)没有办法将一个模板名称别名化为另一个模板名称以使它们看起来相同,因此它永远不会返回误报,并且如果您实际上有一个名为vector的成员,则只能返回假阴性你的派生类。

答案 1 :(得分:1)

正如其他人在评论中所说,通常建议不要继承标准库容器。通常的规则是“首选组合到继承”,即给你的类一个std::vector<T>成员而不是子类化。

无论如何,您遇到的问题是您尝试将vector<Batch>作为vector<vector<T>>传递。由于Batch vector<int>,因此认为vector<Batch> 也是 vector<vector<int>>可能是合理的,但这不是C ++的工作方式 - this question on Stroustrup's FAQ page可以很好地解释原因。

最简单的解决方法是在Batch表示Batch,如

vector<Batch> interleave(const Batch& v, unsigned l);
Batch flatten(const vector<Batch>& w);

虽然你当然可能更喜欢Potatoswatter聪明的SFINAE解决方案以保持一般性。