простые шаблоны C ++, подходящие для контейнеров STL - PullRequest
4 голосов
/ 02 января 2009

Мне нужен такой шаблон, который отлично работает

template <typename container> void mySuperTempalte (const container myCont)
{
    //do something here
}

тогда я хочу специализировать приведенный выше шаблон для std :: string, чтобы я придумал

template <typename container> void mySuperTempalte (const container<std::string> myCont)
{
    //check type of container
    //do something here
}

, который не работает и выдает ошибку. Я хотел бы, чтобы второй пример работал, а затем, если возможно, я хотел бы добавить некоторый код в шаблон, чтобы проверить, использовался ли std :: vector / std :: deque / std :: list, чтобы сделать что-то по-разному в каждом дело. Поэтому я использовал шаблоны, потому что 99% кода одинаковы как для векторов, так и для запросов и т. Д.

Ответы [ 6 ]

7 голосов
/ 02 января 2009

Вы пробовали параметр typename шаблона? Синтаксис немного странный, потому что он эмулирует синтаксис, используемый для объявления такого контейнера. Есть хорошая InformIT статья , объясняющая это более подробно.

template <template <typename> class Container>
void mySuperTemplate(Container<std::string> const& cont) {
}

Обратите внимание, что вы также должны объявить аргумент как ссылку!

Кстати: этот комментарий

//check type of container

мертвая распродажа, что вы делаете что-то не так. Вы не хотите проверить тип контейнера. Вместо этого пользователь более изощренно перегружен, как показано в ответе sep.

7 голосов
/ 02 января 2009

Для специализации:

template<> void mySuperTempalte<std:string>(const std::string myCont)
{
    //check type of container
    //do something here
}

Чтобы специализироваться на векторе:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

Чтобы специализироваться на deque:

template<typename C> void mySuperTempalte (std::deque<C> myCont)
{
    //check type of container
    //do something here
}
5 голосов
/ 02 января 2009

Если я правильно понимаю вашу проблему, у вас есть алгоритм, который будет работать для вектора контейнеров STL, deque и т. Д., Но вы пытаетесь написать специализацию шаблона для строки. Если это так, то вы можете написать обобщенный шаблонный метод, который вы определили в своем вопросе: -

template<typename container> void mySuperTempalte( const container &myCont )
{
    // Implement STL container code
}

Тогда для вашей специализации строки вы объявляете: -

template<> void mySuperTempalte( const container<std::string> &myCont )
{
    // Implement the string code
}

Для любой другой специализации просто измените объявление типа для myCont. Если вам действительно нужно сделать это для контейнеров vector и deque, то сделайте параметр шаблона параметром для типа в этом контейнере, а не в самом контейнере, как предложил Sep.

template<typename C> void mySuperTempalte( const std::vector<C> &myCont)
{
    // check type of container
    // do something here
}

Стоит попытаться избежать этого, заставив вашу первую реализацию работать со всеми контейнерами STL, чтобы облегчить вашу жизнь, тогда вам нужна только специализация для строкового класса. Даже подумайте о преобразовании вашей строки в вектор, чтобы избежать специализации все вместе.

Кстати, я изменил параметр контейнера на ссылку const, я предполагаю, что это именно то, что вам нужно, так как вы все равно объявляете объект const, таким образом вы избегаете копирования.

4 голосов
/ 02 января 2009

Ответы пока кажутся полезными, но я думаю, что я бы использовал другую конструкцию. Я ожидаю, что все контейнеры будут определять value_type, так же как и контейнеры STL. Поэтому я могу написать

inline template <typename C> void mySuperTemplate (C const& myCont)
{
    mySuperTemplateImpl<C, typename C::value_type>(myCont);
}

В общем, проще воздействовать на параметр, который вы извлекли явно.

3 голосов
/ 02 января 2009

@ * 1001 Сентябрь *

«Простое» решение

Ответ, опубликованный 'sep', довольно хорош, вероятно, достаточно хорош для 99% разработчиков приложений, но может повторить некоторые улучшения, если он является частью интерфейса библиотеки,

Чтобы специализироваться на векторе:

template<typename C> void mySuperTempalte (std::vector<C> myCont)
{
    //check type of container
    //do something here
}

Это будет работать при условии, что вызывающая сторона не использует std :: vector. Если это работает достаточно хорошо для вас, чтобы специализироваться на векторе, списке и т. Д., Остановитесь здесь и просто используйте это.

Более полное решение

Во-первых, обратите внимание, что вы не можете частично специализировать шаблоны функций - вы можете создавать перегрузки. И если два или более из них совпадают в одинаковой степени, вы получите ошибки «неоднозначной перегрузки». Поэтому нам нужно сделать ровно одно совпадение в каждом случае, который вы хотите поддержать.

Один из методов для этого заключается в использовании метода enable_if - enable_if позволяет выборочно исключать перегрузки шаблонов функций из списка возможных совпадений с помощью неясного правила языка ... в основном, если какое-либо логическое выражение ложно, перегрузка «невидимый». Посмотрите SFINAE для получения дополнительной информации, если вам интересно.

* * Пример тысяча двадцать три. Этот код может быть скомпилирован из командной строки с помощью MinGW (g ++ parameterize.cpp) или VC9 (cl / EHsc parameterize.cpp) без ошибок:
#include <iostream>
#include <vector>
#include <string>
using namespace std;

template <bool B, class T> struct enable_if {};
template <class T> struct enable_if<true, T> { typedef T type; };

template <class T, class U> struct is_same { enum { value = false }; };
template <class T> struct is_same<T,T> { enum { value = true }; };

namespace detail{
    // our special function, not for strings
    //   use ... to make it the least-prefered overload
    template <class Container>
    void SpecialFunction_(const Container& c, ...){
        cout << "invoked SpecialFunction() default\n";
    }

    // our special function, first overload:
    template <class Container>
    // enable only if it is a container of mutable strings
    typename enable_if<
        is_same<typename Container::value_type, string>::value, 
        void
    >::type
    SpecialFunction_(const Container& c, void*){
        cout << "invoked SpecialFunction() for strings\n";
    }
}

// wrapper function
template <class Container>
void SpecialFunction(const Container& c){
    detail::SpecialFunction_(c, 0);
}

int main(){
    vector<int> vi;
    cout << "calling with vector<int>\n";
    SpecialFunction(vi);

    vector<string> vs;
    cout << "\ncalling with vector<string>\n";
    SpecialFunction(vs);
}

Выход:

d:\scratch>parameterize.exe calling
with vector<int> invoked
SpecialFunction() default

calling with vector<string> invoked
SpecialFunction() for strings

d:\scratch>
1 голос
/ 02 января 2009

Является ли это хорошим дизайном или нет, оставлено для дальнейшего обсуждения. В любом случае, вы можете определить тип контейнера, используя частичную специализацию шаблона. В частности:

enum container_types
{
   unknown,
   list_container,
   vector_container
};

template <typename T>
struct detect_container_
{
   enum { type = unknown };
};

template <typename V>
struct detect_container_< std::vector<V> > // specialization
{
   enum { type = vector_container };
};

template <typename V>
struct detect_container_< std::list<V> >
{
   enum { type = list_container };
};

// Helper function to ease usage
template <typename T>
container_types detect_container( T const & )
{
   return static_cast<container_types>( detect_container_<T>::type );
}

int main()
{
   std::vector<int> v;

   assert( detect_container( v ) == vector_container );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...