2012-04-18 3 views
2

У меня есть класс шаблона, представляющий массив числовых значений.частичная специализация функции в классе шаблона

Я хочу, чтобы этот класс работал для любого типа числового значения (например, int, double и т. Д.) И трех типов контейнеров (std :: vector, std :: deque и std :: list).

Вот соответствующие биты реализации для моей конкретной задачи:

template < typename Numeric_t, typename Container = std::vector<Numeric_t> > 
class Array { 

    // field member 
    Container m_data; 

    // other stuff here 
    // ... 

    // random element access for std::vector and std::deque 
    Numeric_t & operator[] (unsigned int index) { return m_data[index]; } 

    // random element access for std::list 
    Numeric_t & operator [] (unsigned int index) { 
    std::list<Numeric_t> :: iterator it = m_data.begin(); 
    std::advance(it, index); 
    return *it; 
    } 

} 

Конечно, компилятор не позволяет мне перегружать оператор [].

Что мне нужно - это частичная специализация для operator [] для std :: list, но специализация частичного шаблона не допускается ни на C++.

(Я знаю, что доступ к случайным элементам неэффективен для списка, но здесь дело не в этом).

В идеале, в коде клиента я хотел бы использовать класс Array, как это:

Array < int, std::vector<int> > vec; 
Array < int, std::list<int> > lst; 

// fill arrays here 
// ... 

std::cout << vec[0] << std::endl; 
std::cout << lst[0] << std::endl; 

После долгих исследований я не смог найти рабочее решение.

Что было бы самым элегантным способом решения этой проблемы?

Благодарим за помощь.

+0

Я думаю, вы имеете в виду «переопределить», а не «перегружать» ... но я думаю, вам нужна специализация всего класса «Array» для случая, когда «Контейнер» является «списком». – sje397

+0

Вы пробовали написать специализацию для всего класса? Если у вас есть код, не относящийся к типам шаблонов, вы можете написать базовый класс шаблона и сделать ваши специализированные классы унаследованными от этой базы. – smichak

+0

У нас есть вопрос по этому вопросу –

ответ

1

Чистое решение заключается в использовании специализированной специализированной специализированной специализации. Различные специализации могут быть получены из одного общего базового класса, чтобы совместно использовать общий код.

Напишите класс ArrayBase, содержащий весь код, который не зависит от конкретного типа контейнера и который предоставляет доступ к контейнеру, защищая его или делая Array классом друзей.

template <class Numeric_t, class Container> 
class Array 
    : public ArrayBase<Numeric_t, Container> 
{ 
    // Container specific code, generic version that works for all containers. 
}; 

template <class Numeric_t> 
class Array<Numeric_t, std::vector<Numeric_t>> 
    : public ArrayBase<Numeric_t, std::vector<Numeric_t>> 
{ 
    // Optimized code for std::vector. 
} 

Другой подход: Вы также можете написать статическую функцию-член, содержащий код для доступа к idx -ю запись контейнера и специализироваться эту функцию:

template <class Numeric_t, class Container> 
class Array 
{ 
    template <class Cont> 
    static Numeric_t get(Cont const& container, unsigned int idx) 
    { 
    std::list<Numeric_t>::iterator it = container.begin(); 
    std::advance(it, idx); 
    return *it; 
    } 

    template <> 
    static Numeric_t get(std::vector<Numeric_t> const& container, unsigned int idx) 
    { 
    return container[idx]; 
    } 

    public: 
    Numeric_t operator[](unsigned int idx) const { return get(m_data, idx); } 
}; 

Я извините, это не работает. Я забыл, что вы не можете специализировать статические функции-члены ... снова.

Другой альтернативой является использование SFINAE, но это неидиоматическое использование, и я бы не рекомендовал его в этом случае.

+0

Большое спасибо.Решение 1, вероятно, более чистое, но решение 2 - это то, что я ищу. Однако мне пришлось добавить ключевое слово 'static' перед объявлениями функций и изменить шаблон <>' на 'template ' во втором определении функции 'get'. Кроме того, мне интересно, может ли этот подход повлиять на производительность для std :: vector на основе Array по сравнению с исходной реализацией. – kokozul