Читал Страуструпа, много думал, но не все понял.
Явная специализация нужна для задания поведения шаблонной функции специфичного для переданных параметров, так? Причем функция выводится по параметрам.
Допустим, я хочу написать шаблонную функцию сравнения и реализовать две специализации. Одну принимающие сами объекты, а другую — указатели на объекты.
То есть, идея такая:
template<class T> bool cmp(T a, T b) {
cout << "General template function called" << endl;
return (a<b);
}
template<class T> bool cmp(const T* a, const T* b) {
cout << "Pointer template function called" << endl;
return (*a<*b);
}
int j=5, i=7;
cmp(g, j);
cmp(&g, &j);
Разумеется, ничего не выходит — оба раза вызывается первая функция. Как-то можно вызвать требуемую? Или я вообще ничего не понял вовсе?
Спасибо.
Здравствуйте, UGN, Вы писали:
UGN>Здравствуйте, Аноним, Вы писали:
А>>template<> А>>bool cmp<int*>(int* a, int* b) А>>{ А>> cout << "Pointer template function called" << endl; А>> return (*a<*b); А>>}
UGN>И так для каждого типа?
UGN>ЗЫ: Как же это все-таки сделать?
Так что хочется то?
Вообще для pointers, или для конкретного типа?
Если вообще для Pointers, то достаточно из оригинального примера убрать const
Здравствуйте, e-Xecutor, Вы писали:
EX>Так что хочется то? EX>Вообще для pointers, или для конкретного типа?
Что хочется Vamp, я не знаю. А мне теперь хочется для указателей вообще.
Я тут тоже читаю 13 главу. Только опытов еще не ставил.
EX>Если вообще для Pointers, то достаточно из оригинального примера убрать const
Пробовал?
VC7 жалуется на неоднозначность.
Здравствуйте, UGN, Вы писали:
UGN>Здравствуйте, e-Xecutor, Вы писали:
EX>>Так что хочется то? EX>>Вообще для pointers, или для конкретного типа? UGN>Что хочется Vamp, я не знаю. А мне теперь хочется для указателей вообще. UGN>Я тут тоже читаю 13 главу. Только опытов еще не ставил.
EX>>Если вообще для Pointers, то достаточно из оригинального примера убрать const UGN>Пробовал? UGN>VC7 жалуется на неоднозначность.
#include <iostream>
using namespace std;
template<class T>
bool cmp(const T& a, const T& b)
{
cout << "General template function called" << endl;
return (a<b);
}
template<class T>
bool cmp(T* a, T* b)
{
cout << "Pointer template function called" << endl;
return (*a<*b);
}
void main()
{
int j=5, i=7;
cmp(i, j);
cmp(&i, &j);
const int a=1,b=2;
cmp(a,b);
cmp(&a,&b);
}
нормально компиляется и работает.
Но! Для const указателей и просто указателей сгенерятся две разные функции
Здравствуйте, UGN, Вы писали:
UGN>Здравствуйте, e-Xecutor, Вы писали:
EX>>Но! Для const указателей и просто указателей сгенерятся две разные функции
UGN>Да это понятно. Я у себя const сразу убрал...
UGN>Твой вариант у меня не работает... (VC7)
Попробовал:
vc7 от VS.NET 2003 13.10.3077
icl 7.1 7.1 Build 20030307Z
bcc32 5.6
везде компиляется и работает так как надо.
UGN>То ли лыжи не едут...
UGN>Кстати, мне бы хотелось видеть первый шаблон в форме
UGN>
UGN>template<class T> bool cmp( T a, T b)
UGN>а не как у тебя
UGN>template<class T> bool cmp(const T& a, const T& b)
UGN>
Ну... на здоровье
И так тоже компиляется и работает.
Только в твоём случае если T!= pod type может получится нехорошо...
Конст — не конст дела не меняет. Специализировать для каждого типа (инт, флоат, ...) — совершенно не хочется. Идея именно такая, как ее понял UGN. Написать две реализации, одна из которых будет работать с самим объектом, а вторая с указателем на него.
Здравствуйте, e-Xecutor, Вы писали:
UGN>>Кстати, мне бы хотелось видеть первый шаблон в форме
UGN>>
UGN>>template<class T> bool cmp( T a, T b)
UGN>>а не как у тебя
UGN>>template<class T> bool cmp(const T& a, const T& b)
UGN>>
EX>Ну... на здоровье EX>И так тоже компиляется и работает.
EX>Только в твоём случае если T!= pod type может получится нехорошо...
Как раз для этого был придуман boost::reference_wrapper<>.
#include <boost/ref.hpp>
template<class T> bool cmp( T a, T b);
struct some {};
void f()
{
some a, b;
cmp(boost::ref(a), boost::ref(b)); // накормим шаблон ссылками
}
template<class T>
bool cmp(const T& a, const T& b)
{
cout << "General template function called" << endl;
return (a<b);
}
template<class T>
bool cmp(T* a, T* b )
{
cout << "Pointer template function called" << endl;
return (*a<*b);
}
int g=5, i=7;
cmp(g, i);
cmp(&g, &i);
Работает именно так, как хотелось. А если вставить в сиганатуру второй функции const, не работает. Разве const в данном случае не запрещает просто изменять значение переменной через указатель, одновременно разрешая передавать адреса константных объектов?
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Частичную специализацию шаблонов функций, в принципе, не поддерживают никакие компиляторы. ПК>По крайней мере, стандарт ее точно не разрешает.
Точно. У БС пример с классами... Куда смотрели мои глаза?
U>>> template<class T> bool cmp( T a, T b)
U>>> template<class T> bool cmp < T* > ( T* a, T* b)
U>>>
P>> Это частичная специализация, которую версии Visual C++ меньше 7.1 не P>> поддерживают в принципе ПК> Частичную специализацию шаблонов функций, в принципе, не ПК> поддерживают никакие компиляторы. По крайней мере, стандарт ее точно не ПК> разрешает.
Просмотрел, что это не методы класса.
Пора отдыхать
Здравствуйте, UGN, Вы писали:
ПК>> Частичную специализацию шаблонов функций <...> стандарт <...> точно не разрешает.
U> А почему решили не делать такое с функциями?
Потому что посчитали, что раз есть перегрузка шаблонов функций, то частичная специализация
для них не нужна.
Это, в некотором роде, спорное утверждение. См., например: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2001/n1295.htm.
Вкратце там сказано, что в namespace std нельзя добавлять перегруженные функции/шаблоны функций,
поэтому некоторые стандартные компоненты "подменить" нельзя. Следствием этого является, в частности,
то, что перегрузить std::swap для своих шаблонов нельзя.
С другой стороны, стандарт не вполне точен в отношении того, как именно разработчики стандартной
библиотеки должны вызывать стандартные функции: используя полностью квалифицированные имена, или
нет (дефекты #225 и #229 стандартной библиотеки), поэтому, вполне возможно, что поиска, зависящего
от аргументов, окажется достаточным для этих целей.
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Bell, Вы писали:
B>тут дело не в частичной специализации, а в overload resolution для шаблонных функций. А у VC6 с этим вроде не все в порядке.
Т.е. на этапе перебора всех подходящих шаблонных функций и
определения более специализированных компилятор считает обе формы идентичными...
Отсюда и неопределенность.
А если сделать перегрузку обычной функцией с подходящими параметрами,
то на следующем этапе компилятор выкинет шаблоны и все будет ок. Так?
Теперь по поводу указателей на константу.
Если определить int n, то &n имеет тип int*.
А для выведенных аргументов применять всяческие приведения нельзя,
поэтому второй шаблон с константными квалификаторами игнорировался
и оба раза использовался общий шаблон. Правильно?
UGN>Т.е. на этапе перебора всех подходящих шаблонных функций и UGN>определения более специализированных компилятор считает обе формы идентичными... UGN>Отсюда и неопределенность.
Да.
UGN>А если сделать перегрузку обычной функцией с подходящими параметрами, UGN>то на следующем этапе компилятор выкинет шаблоны и все будет ок. Так?
Да. Обычная функция имеет преимущество перед шаблонной.
UGN>Теперь по поводу указателей на константу.
UGN>Если определить int n, то &n имеет тип int*. UGN>А для выведенных аргументов применять всяческие приведения нельзя, UGN>поэтому второй шаблон с константными квалификаторами игнорировался UGN>и оба раза использовался общий шаблон. Правильно?
Не совсем понял о чем речь — "второй шаблон" — это где?
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Потому что посчитали, что раз есть перегрузка шаблонов функций, то частичная специализация ПК>для них не нужна.
Понятно...
А вот еще вопросик по 13 главе. С++ Programming Language SE (3)
В самом начале п.13.4.1 Default Template Parameters приводится пример
Explicitly specifying the comparison criteria for each call is tedious. Fortunately, it is easy to pick
a default so that only uncommon comparison criteria have to be explicitly specified. This can be
implemented through overloading:
template< class T, class C >
int compare( const String<T>& str1, const String<T>& str2 ); // compare using Ctemplate< class T >
int compare( const String<T>& str1, const String<T>& str2 ); // compare using Cmp<T>
Собственно вопрос: А почему во втором случае будет использоваться Cmp<T>, откуда он там возьмется?
Я что-то упустил?
Здравствуйте, Bell, Вы писали:
UGN>>Если определить int n, то &n имеет тип int*. UGN>>А для выведенных аргументов применять всяческие приведения нельзя, UGN>>поэтому второй шаблон с константными квалификаторами игнорировался UGN>>и оба раза использовался общий шаблон. Правильно?
B>Не совсем понял о чем речь — "второй шаблон" — это где?
U> template< class T, class C >
U> int compare( const String<T>& str1, const String<T>& str2 ); // compare using C
U> template< class T >
U> int compare( const String<T>& str1, const String<T>& str2 ); // compare using Cmp<T>
U>
U> А почему во втором случае будет использоваться Cmp<T>, откуда он там возьмется?
Ее будет использовать реализация второго варианта. Например, так:
template< class T >
int compare( const String<T>& str1, const String<T>& str2 ) // compare using Cmp<T>
{
return compare<Cmp<T>, T>(str1, str2);
}
Posted via RSDN NNTP Server 1.6 RC1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
U>> А почему во втором случае будет использоваться Cmp<T>, откуда он там возьмется?
ПК>Ее будет использовать реализация второго варианта. Например, так:
ПК>
ПК>template< class T >
ПК>int compare( const String<T>& str1, const String<T>& str2 ) // compare using Cmp<T>
ПК>{
ПК> return compare<Cmp<T>, T>(str1, str2);
ПК>}
ПК>
А, просто другая реализация... А то я уж подумал, что там какая-то магия...
Для первого варианта реализация есть и там используется C, а что со вторым я ниппоньял...
Спасибо.
Здравствуйте, UGN, Вы писали:
UGN>Здравствуйте, Bell, Вы писали:
UGN>>>Если определить int n, то &n имеет тип int*. UGN>>>А для выведенных аргументов применять всяческие приведения нельзя, UGN>>>поэтому второй шаблон с константными квалификаторами игнорировался UGN>>>и оба раза использовался общий шаблон. Правильно?
B>>Не совсем понял о чем речь — "второй шаблон" — это где?
UGN>здесь
UGN>template<class T> bool cmp(T a, T b)
UGN>template<class T> bool cmp(const T* a, const T* b)
UGN>
Ага, теперь ясно.
Тут ты не прав: при overload resolution рассматриваются специализации обоих шаблонов, полученные во время дедуцирования аргументов. Они (специадизации) имеют такие сигнатуры:
Здравствуйте, Bell, Вы писали:
B>Ага, теперь ясно. B>Тут ты не прав: при overload resolution рассматриваются специализации обоих шаблонов, полученные во время дедуцирования аргументов. Они (специадизации) имеют такие сигнатуры: B>
Почему выигрывает первая специализация?
Потому что const int* и просто int* — разные типы... Так?
Компилятор мог бы использовать второй шаблон,
сконвертировав типы аргументов, но это ему запрещено.
Поэтому он выводит нужную реализацию из общего шаблона. Так?
UGN>Почему выигрывает первая специализация? UGN>Потому что const int* и просто int* — разные типы... Так?
Да. UGN>Компилятор мог бы использовать второй шаблон, UGN>сконвертировав типы аргументов,
конечно, если бы не было более подходящего варианта. UGN>но это ему запрещено.
Вовсе нет. убери из кода первый шаблон, и компилятор спокойно организует вызов ыторого. UGN>Поэтому он выводит нужную реализацию из общего шаблона. Так?
Компилятор использует специализацию первого шаблона из-за того того, что полученные типы параметров ближе к реальному типу передаваемых аргументов.