2009-01-02 3 views
4

мне нужен шаблон, как это, которые работают отличнопростые шаблоны C++ подходит для STL контейнеров

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

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

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

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

+0

Непонятно, хотите ли вы специализироваться на различном содержимом или контейнерах. Вы рассматриваете std :: string как хранимый тип неизвестного контейнера? Или вы рассматриваете std :: string как контейнер char? –

ответ

5

Если я понимаю ваша проблема правильно, у вас есть алгоритм, который будет работать для векторных контейнеров 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, тогда сделайте параметр шаблона параметром для типа в этом контейнере, а не самим контейнером, как предложил сентябрь.

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

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

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

7

специализироваться:

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 
} 
+1

Это отвечает на другой вопрос. ;-) –

+0

Я думаю, что он отвечает, даже если не так прямо и очевидно, как мог. –

+0

Только первая специализация; второй и третий случаи - это перегрузки. – MSalters

7

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

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

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

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

//check type of container 

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

+3

Do _NOT_ используйте этот код, так как он не будет работать для контейнеров STL.вектор, список и т. д. не являются шаблонами с одним аргументом, они являются шаблонами, принимающими как минимум два аргумента, где все, кроме первого, имеют значения по умолчанию (разрешено бесконечное количество дополнительных аргументов в качестве деталей реализации). Этот код НЕ переносится. – Aaron

+1

@ Аарон: правда, спасибо, что указали это. Но тогда способ сделать это - использовать аргументы итератора в любом случае вместо контейнера. –

+0

Конрад, хорошая точка. OP, вероятно, должен сказать нам, что он * на самом деле хочет делать :) –

4

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

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

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

1

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

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); 
} 
3

@sep

'Простой' решение

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

To specialize for vector:

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

Это будет работать при условии, что абонент не использует зЬй :: вектор.Если это работает достаточно хорошо для вас, специализироваться на вектор, список и т. Д., Тогда остановитесь здесь и просто используйте это.

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

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

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

Пример. Этот код может быть скомпилирован из командной строки с MinGW (г ++ parameterize.cpp) или VC9 (кл/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

вы пригвоздили его :) Я собирался написать «исправленную» версию своего ответа с помощью boost :: enable_if, но потом выяснил, что вам нужно много вариантов enable_if, если у вас есть больше, чем просто специальная обработка для строки * и все еще общая поддержка для других типов *. но я не думал об эллипсисе. +1! :) –

+0

насчет: шаблона <шаблон <имяТип ELEM, имяТип ALLOC = станд :: Распределитель > класс Container> рядного станд :: IStream и оператор >> (станд :: IStream & в, контейнер и контейнер) { станда :: string string; while (in >> string) { container.push_back (string); } возвращение в; } – Martin

+0

@Martin - интересный, но не портативный. std :: vector разрешено иметь более двух аргументов шаблона (если другие аргументы имеют значения по умолчанию), и в этом случае это не будет шаблон class, поэтому его нельзя было бы вывести вместо Container. – Aaron