Re[9]: специализация std::equal_to<>
От: Аноним  
Дата: 31.08.07 08:19
Оценка:
Здравствуйте, 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 Тип>. Вопрос был в том, почему не срабатывало наследование (см. исходный пост)
Re[10]: специализация std::equal_to<>
От: igna Россия  
Дата: 31.08.07 08:31
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Я Вам на примере показал, что можно специализировать Шаблон<Тип> и Шаблон<const Тип>. Компилятору это понятно, и он выберает соответствующую версию специализации как и ожидается. Почему Вы от этого постоянно отрекаетесь?


Нет, не отрекаюсь, я знаю, что это возможно.

А>Мне как раз и нужно специализировать Шаблон<Тип> и Шаблон<const Тип>. Вопрос был в том, почему не срабатывало наследование (см. исходный пост)


Вот именно в том конкретном случае проблему можно было решить отказом от специализации для const Тип.
Re[11]: специализация std::equal_to<>
От: Аноним  
Дата: 31.08.07 08:35
Оценка:
Здравствуйте, igna, Вы писали:

А>>Мне как раз и нужно специализировать Шаблон<Тип> и Шаблон<const Тип>. Вопрос был в том, почему не срабатывало наследование (см. исходный пост)


I>Вот именно в том конкретном случае проблему можно было решить отказом от специализации для const Тип.

Спасибо за замечаение, но вопрос был немного о другом.
Re[8]: специализация std::equal_to<>
От: Bell Россия  
Дата: 31.08.07 08:57
Оценка: 1 (1) +1
Здравствуйте, Аноним, Вы писали:

А>Как тогда объяснить, что в этом примере выбирается не моя специализация, а дефолтная?

Похоже, что запутались уже все
Попробуем немного упростить исходный пример — т.е. сначала сделаем специализацию для 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*>()
Любите книгу — источник знаний (с) М.Горький
Re[9]: специализация std::equal_to<>
От: Аноним  
Дата: 31.08.07 11:53
Оценка:
Здравствуйте, Bell, Вы писали:

B>Похоже, что запутались уже все

Да, это хорошо у меня получилось

[]

Огромное спасибо за подробный ответ!
Теперь всё стало на свои места, и даже я понял чего хотел
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.