Специализирующая функция-член для не шаблонного класса в C++
Я пытаюсь специализировать функцию-член шаблона не-шаблонного класса, используя шаблонный параметр:
#include <array>
class C
{
public:
template<class Container>
void Foo( Container& )
{
// ...
}
};
template<class T, std::size_t N>
template<>
void C::Foo< std::tr1::array<T,N> >( std::tr1::array<T,N>& )
{
// special
}
Я получаю ошибку "незаконное использование явных аргументов шаблона" с этим. Какой правильный синтаксис, чтобы сделать это действительным?
Обновление:
Возможно я запутал проблему чрезмерным упрощением. Что я действительно хочу сделать, так это специально разобраться с этим одним случаем, когда задействовано зависимое имя, которое, я думаю, может быть тем, что бросает гаечный ключ в работу здесь. Моей первоначальной мыслью было перегрузить функцию как таковую:
class C
{
public:
template<class Iter>
void Foo( Iter )
{
std::cout << "Normal\n";
}
template<class T, std::size_t N>
void Foo( typename std::tr1::array<T,N>::iterator )
{
std::cout << "Special\n";
}
};
int main()
{
C c;
std::tr1::array<int,10> a1;
c.Foo( a1.begin() ); // Doesn't print "Special"!
}
Но специальный Foo не вызывается. Как я могу это сделать?
2 ответа
Только функция-член является шаблонной, что означает, что вы должны использовать только один template<...>
там. Но это также не решит проблему, поскольку вы не можете частично специализировать функцию.
Обычный способ решения проблемы - перегрузка, а не специализация (специализация шаблонных функций не так уж полезна).
struct test {
template <typename Container>
void f( Container& ) { ... }
template <typename T, int N>
void f( std::array<T,N>& ) { ... }
};
Обратите внимание, что разница в том, что это две отдельные функции шаблона (а не специализация).
РЕДАКТИРОВАТЬ: после обновления
Обновление вопроса полностью меняет проблему. Проблема, которую вы видите, состоит в том, что аргумент второй версии является зависимым именем, и как таковой он не выводим. Учитывая вызов функции, компилятор не может определить, какой тип T и интегральная константа N должны соответствовать этому конкретному экземпляру. Рассмотрим другой пример:
template <typename T>
struct inner_int {
typedef int type;
};
template <typename T>
void foo( typename inner_int<T>::type ) {
}
int main() {
foo( inner_int<double>::type() );
}
Когда компилятор обрабатывает вызов в main
он создает экземпляр шаблона и извлекает тип, из которого создает временный, а затем пытается решить, что делать с foo
но в то время он только знает, что он вызывается с int
рвалу... оригинал inner<double>::type
ушел, теперь это просто foo( int() )
и компилятор должен будет попытаться создать экземпляр inner_int
со всеми возможными типами, чтобы определить, подходит ли какой-либо из них, и в худшем случае, как указано выше, многие подойдут.
Частичная специализация шаблона функции недопустима. Из стандарта C++03, §14/2:
Объявление шаблона может появляться только как область видимости пространства имен или декларация области класса. В объявлении шаблона функции идентификатор объявления должен быть именем шаблона (т. Е. Не идентификатором шаблона). [Примечание: в объявлении шаблона класса, если имя класса является идентификатором шаблона, объявление объявляет частичную специализацию шаблона класса.]
Вместо этого вы захотите просто перегрузить свою функцию:
class C
{
public:
template<typename Container>
void Foo(Container&)
{
// ...
}
template<typename T, std::size_t N>
void Foo(std::tr1::array<T, N>&)
{
// special
}
};
РЕДАКТИРОВАТЬ (в ответ на редактирование ОП):
Если вы ищете только обходной путь для этого конкретного сценария, так как std(::tr1)::array<T,N>::iterator
это просто T*
Ваша "специальная" перегрузка может быть:
template<typename T>
void Foo(T*&)
{
// special
}