2013-11-29 3 views
1

Если класс проистекает из вектора, как вы можете преформировать (templated) векторные функции на нем?apply std :: vector <T> функции для класса, полученного из std :: vector

Например, следующий код не будет компилироваться:

#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; для получения желаемого выхода: 0 3 6 9 1 4 7 10 2 5 8 11

+3

Публичное наследство от вектора - плохая идея. – chris

+0

Рассмотрите возможность достижения того, что вы хотите [композиция вместо наследования] (http://en.wikipedia.org/wiki/Composition_over_inheritance). У вас будет много головных болей, пытающихся просто передать данные на вашу векторную базу. –

+0

@SamCristall Я пробовал композицию. Это делает код уродливым, так как мне нужно сделать много особых случаев для шаблонных функций. –

ответ

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

Как уже отмечалось в комментариях, обычно рекомендуется не наследовать стандартные контейнеры библиотек. Обычным правилом является «предпочтение композиции наследования», то есть дать вашему классу член 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); 

хотя, конечно, вы можете предпочесть умное решение SFINAE Potatoswatter для поддержания общности.

Смежные вопросы