2016-07-05 2 views
2

Я пытаюсь написать функцию шаблона, которая будет обрабатывать любые типы аргументов, включая векторы, карты и т. Д., Но у меня возникают проблемы.template specialization on std :: vector <T>

template<class C> 
void foo(C c); 

template<> 
template<class V> 
void foo<std::vector<V> >(std::vector<V> v); 

Компилятор (г ++ 4.9.2-10) будет жаловаться на это:

test.cpp:13:43: error: too many template parameter lists in declaration of ‘void foo(std::vector<V>)’ 
void foo<std::vector<V> >(std::vector<V> v) { 
             ^
test.cpp:13:6: error: template-id ‘foo<std::vector<V> >’ for ‘void foo(std::vector<V>)’ does not match any template declaration 
void foo<std::vector<V> >(std::vector<V> v) { 
    ^
test.cpp:13:43: note: saw 2 ‘template<>’, need 1 for specializing a member function template 
void foo<std::vector<V> >(std::vector<V> v) { 
             ^

Как я могу добиться этого? Я также хочу, чтобы специализироваться на станд :: Карта < станд :: строке, V >

удаления первого шаблона < > линии от специализации по-прежнему не работает (незаконная специализации)

+0

просто есть 'шаблон <класс Container>' и использовать его, как вы контейнер –

+1

[OT]: вы, наверное, хотите передать параметр по константной ссылке, а не по V ALUE. – Jarod42

+0

@ Jarod42 хороший момент, я делаю это все время, но пропустил его здесь ради простоты –

ответ

4

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

template<class C> 
void foo(C c); 

template<class V> 
void foo(std::vector<V> v); // This is an overload, not a specialization! 

Пожалуйста, обратите внимание на разницу с частичной специализацией foo:

template<class C> 
void foo(C c); // 1 

template<class V> 
void foo<std::vector<V>>(std::vector<V> v); // 2 

Здесь 2 - частичная специализация 1, которая не допускается в функции C++ для функции.

+0

Я пробовал это, он не работает, я получаю этот вывод: test.cpp: 12: 43: error: function шаблон частичной специализации «Foo <станд :: вектор >» не допускается недействительными Foo <станд :: вектор > (станд :: вектор v) { ^ –

+0

не @BogdanIonitza Существует нет '<станд :: вектор > 'между' foo' и открывающей скобкой в ​​моем коде. Если вы добавите его, вы пытаетесь частично специализировать функцию, но вы не можете сделать это на C++, вам нужно перегрузить ее (как в моем коде). – Holt

+0

Вы правы, я пропустил этот аспект. Спасибо, кажется, работает :) –

2

Возможно, вам будет удобно перегружать его на основе свойств контейнера.

Это позволяет немного больше гибкости с точки зрения принятия ссылок, ссылок на константы и ссылок на r-значение при одновременном написании функции.

Вот небольшой пример, который реализует шаблон foo для всего, что имеет begin() и end() метода, за исключением станда :: строк, который получает свою собственную версию foo через перегрузку нешаблонном:

#include <vector> 
#include <map> 
#include <iostream> 
#include <iomanip> 

// trait type to determine whether something models a range. 
template<class T> 
struct is_range 
{ 
    template <class Y> static auto has_begin(T*p) -> decltype(p->begin(), void(), std::true_type()); 
    template <class Y> static auto has_begin(...) -> decltype(std::false_type()); 

    template <class Y> static auto has_end(T*p) -> decltype(p->end(), void(), std::true_type()); 
    template <class Y> static auto has_end(...) -> decltype(std::false_type()); 

    static constexpr bool value = decltype(has_begin<T>(0))::value && decltype(has_end<T>(0))::value; 
}; 


// specialised mini-functor for dealing with corner cases 
template<class T> 
struct emitter 
{ 
    std::ostream& operator()(std::ostream& os, const T& t) const { 
     return os << t; 
    } 
}; 

template<class T, class U> 
struct emitter<std::pair<T, U>> 
{ 
    std::ostream& operator()(std::ostream& os, const std::pair<T, U>& p) const 
    { 
     return os << "(" << p.first << ", " << p.second << ")"; 
    } 
}; 

// a version of foo which works for all known containers, whether temporararies or references 
template<class Container, 
std::enable_if_t<is_range<std::decay_t<Container>>::value and not std::is_same<std::decay_t<Container>, std::string>::value>* = nullptr 
> 
void foo(Container&& c) 
{ 
    // do things with c.begin(), c.end() 
    bool first = true; 
    for (auto& x : c) { 
     using emitter_type = emitter<std::decay_t<decltype(x)>>; 
     auto emit = emitter_type(); 
     if (first) { 
      first = false; 
     } else { 
      std::cout << ", "; 
     } 
     emit(std::cout, x); 
    } 
    std::cout << std::endl; 
} 

// overload for std string 

void foo(const std::string& s) 
{ 
    std::cout << std::quoted(s) << std::endl; 
} 

int main() 
{ 
    using namespace std::literals; 

    foo(std::map<std::string, std::string> { 
     { 
      { { "foo" }, { "bar" } }, 
      { { "aaaa" }, { "bbbbb" } } 
     } 
    }); 
    foo(std::vector<std::string> { 
     { "foo" }, 
     { "bar" }, 
     { "xxxx" }, 
     { "yyyy" } }); 

    foo("hello"s); 

} 

ожидается выход:

(aaaa, bbbbb), (foo, bar) 
foo, bar, xxxx, yyyy 
"hello" 
Смежные вопросы