Здравствуйте, igna, Вы писали:
А>>Как тогда объяснить, что в этом примере выбирается не моя специализация, а дефолтная?
I>А>>typedef int theType;
А>>template<>
А>>struct std::equal_to<theType> :
А>> binary_function<theType, theType, bool>
А>>{
А>> bool operator()(const theType s1, const theType s2) const
А>> { return true; }
А>>};
А>>void f()
А>>{
А>> const theType sz = 0;
А>> std::equal_to<const theType>()(sz, sz);
А>>}
I>
I>Ну а лишний const тебе тут помог? Куда ты его вставил, чтоб поехало как хочется?
Я не говорю о тут, я говорю в принципе.
Я Вам на примере показал, что можно специализировать Шаблон<Тип> и Шаблон<const Тип>. Компилятору это понятно, и он выберает соответствующую версию специализации как и ожидается. Почему Вы от этого постоянно отрекаетесь?
Мне как раз и нужно специализировать Шаблон<Тип> и Шаблон<const Тип>. Вопрос был в том, почему не срабатывало наследование (см. исходный пост)
Здравствуйте, Аноним, Вы писали:
А>Как тогда объяснить, что в этом примере выбирается не моя специализация, а дефолтная?
Похоже, что запутались уже все
Попробуем немного упростить исходный пример — т.е. сначала сделаем специализацию для const int (аналог
const wchar_t*const ):
template<>
struct std::equal_to<const int> :
binary_function<const int, const int, bool>
{
bool operator()(const int s1, const int s2) const
{ return false; }
};
Далее пробуем использовать equal_to с типом int (аналог const wchar_t*)
void f()
{
const int sz = 0;
std::equal_to<int>()(sz, sz);
}
Тип int, конечно же, отличен от const int. Поэтому специализация не подходит, и компилятор выбирает базовый шаблон. При этом тип переменной
sz не играет роли — выбор специализации происходит исключительно исходя из параметра шаблона equal_to<
int> — т.е. int.
Теперь пример, приводящий к той же самой ошибке, что и в исходном посте:
int main()
{
const int sz = 0;
std::vector<int> v;
std::find_if(v.begin(), v.end(),
std::bind1st(std::equal_to<const int>(), sz));//Error
return 0;
}
Смотрим определение шаблона binder1st:
template<class _Fn2>
class binder1st
: public unary_function<typename _Fn2::second_argument_type,
typename _Fn2::result_type>
{ // functor adapter _Func(stored, right)
public:
typedef unary_function<typename _Fn2::second_argument_type,
typename _Fn2::result_type> _Base;
typedef typename _Base::argument_type argument_type;
typedef typename _Base::result_type result_type;
binder1st(const _Fn2& _Func,
const typename _Fn2::first_argument_type& _Left)
: op(_Func), value(_Left)
{ // construct from functor and left operand
}
result_type operator()(const argument_type& _Right) const
{ // apply functor to operands
return (op(value, _Right));
}
result_type operator()(argument_type& _Right) const
{ // apply functor to operands
return (op(value, _Right));
}
protected:
_Fn2 op; // the functor to apply
typename _Fn2::first_argument_type value; // the left operand
};
Видим 2 перегрузки operator()
result_type operator()(const argument_type& _Right) const
result_type operator()(argument_type& _Right) const
argument_type — это _Fn2::second_argument_type, т.е.
const int:
struct std::equal_to<const int> :
binary_function<const int, const int, bool>
Таким образом сигнатуры операторов () получаются такими:
result_type operator()(const const int& _Right) const
result_type operator()(const int& _Right) const
В соответсвии с 7.1.5/1 "лишние" const-квалификаторы в первой перегрузке игрорируются, и получается
result_type operator()(const int& _Right) const
result_type operator()(const int& _Right) const
Т.е. сигнатуры идентичны — это и есть причина ошибки
Чтобы избавиться от ошибки, нужно изменить параметры binary_function в свециализации:
template<>
struct std::equal_to<const int> :
binary_function</*const */int, /*const */int, bool>
ну или в оригинальном примере:
template<>
struct std::equal_to<const wchar_t*const> :
binary_function<const wchar_t*/*const*/, const wchar_t*/*const*/, bool>
Теперь о проблемах:
Специализация сущностей из std встроенными типами ведет к неопределенному поведению.
Использованный синтаксис специализации некорректен, хотя компиляторы VC и переваривают его. Правильно нужно так:
namespace std
{
template<>
struct std::equal_to<const int> :
binary_function<int, int, bool>
{
/**/
};
}
Подводя итог: свой функтор избавит от сомнительной специализации, и упростит использование — не нужно будет явно указывать параметр шаблона:
struct my_equal_to : binary_function<const wchar_t*, const wchar_t*, bool>//Не забываем убрать лишний const :)
{
bool operator()(const wchar_t*const s1, const wchar_t*const s2) const
{ return 0 == _wcsicmp(s1, s2); }
};
...
std::find_if(v.begin(), v.end(), std::bind1st(my_equal_to(), sz));//Сравни с std::equal_to<const wchar_t*>()
Здравствуйте, Bell, Вы писали:
B>Похоже, что запутались уже все
Да, это хорошо у меня получилось
[]
Огромное спасибо за подробный ответ!
Теперь всё стало на свои места, и даже я понял чего хотел