специализировать шаблон функции для шаблона класса - PullRequest
2 голосов
/ 23 августа 2011

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

namespace std { //declarations of predefined indexable types
    template <class T, class A> class vector;
    //others are here too, but all have the same issue 
}
//default indexer
template <class T>
double indexer(const T& b) { //this seems to work fine
    return b.getIndex();
}
// base types
template<> double indexer<char>(const char& b) { return double(b); }
//other primitives are here too, and work fine
// standard library
template<class T, class A> 
double indexer<std::vector<T,A>>(const std::vector<T,A>& b) 
{ return b.empty() ? 0 : indexer(*b.cbegin()); } //line with error

сообщение об ошибке:

error C2768: 'indexer' : illegal use of explicit template arguments

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

template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>);} //default wrapper

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

Ответы [ 3 ]

2 голосов
/ 24 августа 2011

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

используйте вместо этого перегрузку:

namespace std { //declarations of predefined indexable types
       template <class T, class A> class vector;
}
//default indexer
template <class T>
double indexer(const T& b) { return b.getIndex(); }

double indexer(const char& b) { return double(b); }

template<class T, class A>
double indexer(const std::vector<T,A>& b)
{ return b.empty() ? 0 : indexer(*b.cbegin()); }
1 голос
/ 24 августа 2011

Поскольку функции не могут быть частично специализированными, я могу заменить функции индексатора функциональными объектами. Кажется, это работает нормально и решает все мои проблемы.

namespace std { //declarations of predefined indexable types
    template <class T, class A> class vector;
}
template <class T>
struct indexer { 
    double operator()(const T& b) const 
    { return b.getIndex(); } 
};
template<> struct indexer<char> { 
    double operator()(const char& b) const 
    { return double(b); } 
};
template<class T, class A> struct indexer<std::vector<T,A>> { 
    double operator()(const std::vector<T,A>& b) const 
    { return b.empty() ? 0 : indexer(*b.cbegin()); } 
};

template<class T, class function>
double A(T a, function F) { return F(a);} //complicated
template<class T>
double A(T a) {return A(a, indexer<T>());} //default wrapper
0 голосов
/ 24 августа 2011

Вот решение, основанное исключительно на перегрузках, с использованием шаблонов с вариациями в стиле C ++ 11:

template <typename T>
T print(const T & t)
{
  std::cout << t << std::endl;
  return t;
}

template <template <typename...> class Container, typename ...Args>
typename Container<Args...>::value_type print(const Container<Args...> & v)
{
  typedef typename Container<Args...>::value_type T;

  if (v.empty()) std::cout << "nil" << std::endl;
  else std::cout << *v.begin() << std::endl;

  return v.empty() ? T() : *v.begin();
}

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

template <template <typename...> class Container, typename ...Args>
typename std::enable_if<is_container<Container<Args...>>::value,
                        typename Container<Args...>::value_type>::type
print(const Container<Args...> & v)
{
  /* ... */
}
...