специализация std::equal_to<>
От: Аноним  
Дата: 30.08.07 13:18
Оценка:
Есть вектор строчек и специализация std::equal_to<> для этих строчек.
template<>
struct std::equal_to<const wchar_t*const> :
    binary_function<const wchar_t*const, const wchar_t*const, bool>
{
    bool operator()(const wchar_t*const s1, const wchar_t*const s2) const
        { return 0 == _wcsicmp(s1, s2); }
};


Лучше бы тут иметь свой предикат, но у нас так исторически сложилось

Далее std::equal_to<> специализируется для типа const wchar_t*. Есть два варианта специализации:
template<>
struct std::equal_to<const wchar_t*> : // (1)
    std::equal_to<const wchar_t*const>
{
};

и
template<>
struct std::equal_to<const wchar_t*> : // (2)
    binary_function<const wchar_t*, const wchar_t*, bool>
{
    bool operator()(const wchar_t* s1, const wchar_t* s2) const
        { return 0 == _wcsicmp(s1, s2); }
};


Вопрос в том, почему при специализации (1) происходит ошибка компиляции?
Второй вариант компилируется без ошибок.

Вот код, вызывающий ошибку:
    const wchar_t* sz = 0;
    std::vector<const wchar_t*> v;

    std::find_if(v.begin(), v.end(),
        std::bind1st(std::equal_to<const wchar_t*>(), sz));  // line 890


А вот и сама ошибка(VS2005SP1) :
d:\program files\microsoft visual studio 8\vc\include\functional(282) : error C2535: 'bool std::binder1st<_Fn2>::operator ()(const wchar_t *const &) const' : member function already defined or declared
        with
        [
            _Fn2=std::equal_to<const wchar_t*>
        ]
        d:\program files\microsoft visual studio 8\vc\include\functional(276) : see declaration of 'std::binder1st<_Fn2>::operator ()'
        with
        [
            _Fn2=std::equal_to<const wchar_t*>
        ]
        d:\myprojects\test2005\test2005\test2005.cpp(890) : see reference to class template instantiation 'std::binder1st<_Fn2>' being compiled
        with
        [
            _Fn2=std::equal_to<const wchar_t*>
        ]

где
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 // line 276
        {    // apply functor to operands
        return (op(value, _Right));
        }

    result_type operator()(argument_type& _Right) const
        {    // apply functor to operands              // line 282
        return (op(value, _Right));
        }

protected:
    _Fn2 op;    // the functor to apply
    typename _Fn2::first_argument_type value;    // the left operand
    };
Re: специализация std::equal_to<>
От: Bell Россия  
Дата: 30.08.07 13:47
Оценка:
Здравствуйте, Аноним, Вы писали:

Я бы начал отсюда:

17.4.3.1 Reserved names
It is undefined for a C + + program to add declarations or definitions to namespace std or namespaces
within namespace std unless otherwise specified. A program may add template specializations for any
standard library template to namespace std. Such a specialization (complete or partial) of a standard
library template results in undefined behavior unless the declaration depends on a user-defined name of
external linkage
and unless the specialization meets the standard library requirements for the original template.


Мне кажется, что тут самое место вспомнить фразу "Лучше бы тут иметь свой предикат"
Любите книгу — источник знаний (с) М.Горький
Re: специализация std::equal_to<>
От: igna Россия  
Дата: 30.08.07 14:07
Оценка:
Здравствуйте, Аноним, Вы писали:

А>struct std::equal_to<const wchar_t*const> :


Зачем тебе здесь второй const?

Подставь свой тип вместо аргумента operator():

А>    result_type operator()(const argument_type& _Right) const // line 276
А>        {    // apply functor to operands
А>        return (op(value, _Right));
А>        }

А>    result_type operator()(argument_type& _Right) const
А>        {    // apply functor to operands              // line 282
А>        return (op(value, _Right));
А>        }


Получающийся тип одинаков в обоих случаях.
Re[2]: специализация std::equal_to<>
От: igna Россия  
Дата: 30.08.07 14:16
Оценка:
Здравствуйте, Bell, Вы писали:

B>Мне кажется, что тут самое место вспомнить фразу "Лучше бы тут иметь свой предикат"


С советом согласен, но спрашивающему не помогло бы. Въехал бы в точности туда же.
Re[3]: специализация std::equal_to<>
От: Bell Россия  
Дата: 30.08.07 15:01
Оценка: 3 (1)
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Bell, Вы писали:


B>>Мне кажется, что тут самое место вспомнить фразу "Лучше бы тут иметь свой предикат"


I>С советом согласен, но спрашивающему не помогло бы. Въехал бы в точности туда же.

Согласен отчасти:
Комо, к примеру, такой пример скомпилит:
struct wcht_equal_to :
    binary_function<const wchar_t*const, const wchar_t*const, bool>
{
    bool operator()(const wchar_t*const s1, const wchar_t*const s2) const
        { return true;/*0 == _wcsicmp(s1, s2);*/ }
};


int main()
{
   const wchar_t* sz = 0;
    std::vector<const wchar_t*> v;

    std::find_if(v.begin(), v.end(),
        std::bind1st(wcht_equal_to(), sz));
   return 0;
}

потому что по стандарту в классе binder1st предусмотрена только одна перегрузка operator():

20.3.6.1 Class template binder1st [lib.binder.1st]

template <class Operation>
class binder1st
: public unary_function<typename Operation::second_argument_type,
   typename Operation::result_type> {
protected:
   Operation op;
   typename Operation::first_argument_type value;
public:
   binder1st(const Operation& x,
      const typename Operation::first_argument_type& y);
   typename Operation::result_type
      operator()(const typename Operation::second_argument_type& x) const;
};


Впрочем, вариант operator(), принимающий неконстантную ссылку тоже может быть полезен

Так что нужно использовать boost::bind, и не заботиться о "лишних" const-ах
struct wcht_equal_to :
    binary_function<const wchar_t*const, const wchar_t*const, bool>
{
    bool operator()(const wchar_t*const s1, const wchar_t*const s2) const
        { return 0 == _wcsicmp(s1, s2); }
};

int main()
{
   const wchar_t* sz = 0;
    std::vector<const wchar_t*> v;

    std::find_if(v.begin(), v.end(),
       boost::bind(wcht_equal_to(), sz, _1));
   return 0;
}

Да и binary_function в этом случае тоже можно не использовать...
Любите книгу — источник знаний (с) М.Горький
Re[4]: специализация std::equal_to<>
От: igna Россия  
Дата: 30.08.07 15:13
Оценка:
Здравствуйте, Bell, Вы писали:

B>struct wcht_equal_to :
B>    binary_function<const wchar_t*const, const wchar_t*const, bool>
B>{
B>    bool operator()(const wchar_t*const s1, const wchar_t*const s2) const
B>        { return true;/*0 == _wcsicmp(s1, s2);*/ }
B>};


А пользу какую-нибудь от использования в этом случае const wchar_t*const вместо const wchar_t* придумать можно?
Re[5]: специализация std::equal_to<>
От: Bell Россия  
Дата: 30.08.07 15:19
Оценка:
Здравствуйте, igna, Вы писали:

I>А пользу какую-нибудь от использования в этом случае const wchar_t*const вместо const wchar_t* придумать можно?

Кроме банального "запретить изменение значения указателя" ничего в голову не приходит.
А может быть кому-то нравится обилие const-ов в коде, или просто придает уверенности
Любите книгу — источник знаний (с) М.Горький
Re[2]: специализация std::equal_to<>
От: Аноним  
Дата: 30.08.07 15:23
Оценка:
Здравствуйте, igna, Вы писали:


I>Зачем тебе здесь второй const?

чтобы работало и для такого типа тоже (например, const LPCSTR)
Re[3]: специализация std::equal_to<>
От: igna Россия  
Дата: 30.08.07 15:33
Оценка: 1 (1) +1
Здравствуйте, Аноним, Вы писали:

А>чтобы работало и для такого типа тоже (например, const LPCSTR)


И без второго const будет работать.
Re[2]: специализация std::equal_to<>
От: Аноним  
Дата: 30.08.07 15:40
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Аноним, Вы писали:


B>Я бы начал отсюда:

B>

B>17.4.3.1 Reserved names
B>It is undefined for a C + + program to add declarations or definitions to namespace std or namespaces
B>within namespace std unless otherwise specified. A program may add template specializations for any
B>standard library template to namespace std. Such a specialization (complete or partial) of a standard
B>library template results in undefined behavior unless the declaration depends on a user-defined name of
B>external linkage
and unless the specialization meets the standard library requirements for the original template.


B>Мне кажется, что тут самое место вспомнить фразу "Лучше бы тут иметь свой предикат"


А как понимать "the declaration depends on a user-defined name of external linkage"?
Можно маленький примерчик?
Re[4]: специализация std::equal_to<>
От: Аноним  
Дата: 30.08.07 15:48
Оценка:
Здравствуйте, igna, Вы писали:

I>Здравствуйте, Аноним, Вы писали:


А>>чтобы работало и для такого типа тоже (например, const LPCSTR)


I>И без второго const будет работать.

Как он может тоже работать, если это другой тип?
Будет, конечно, работать, но не правильно
Потому что выберется дефолтная версия std::equal_to<>, а моя перегруженная — нет
Re[5]: специализация std::equal_to<>
От: igna Россия  
Дата: 30.08.07 16:01
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Потому что выберется дефолтная версия std::equal_to<>, а моя перегруженная — нет


Для const LPCSTR выберется та же твоя перегруженная что и для LPCSTR.
Re[6]: специализация std::equal_to<>
От: igna Россия  
Дата: 30.08.07 16:08
Оценка:
I>Для const LPCSTR выберется та же твоя перегруженная что и для LPCSTR.

Ты же не объявляешь в дополнение к void f(int) еще и void f(const int). Собственно тут тебе и компилятор не позволит, как впрочем не позволил и в твоем случае.
Re[3]: специализация std::equal_to<>
От: Bell Россия  
Дата: 31.08.07 06:32
Оценка:
Здравствуйте, Аноним, Вы писали:

А>А как понимать "the declaration depends on a user-defined name of external linkage"?

Можно добавлять только специализации, зависящие от определенных пользователем типов.

А>Можно маленький примерчик?


struct test{};//определенный пользователем тип

namespace std
{
template<>
struct equal_to<test>{/**/};//Можно, ибо test -  определенный пользователем тип.

template<>
struct equal_to<const wchar_t*>{/**/};//Нельзя, ибо wchar_t - встроенный тип.
}
Любите книгу — источник знаний (с) М.Горький
Re[4]: специализация std::equal_to<>
От: Аноним  
Дата: 31.08.07 06:47
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Аноним, Вы писали:


А>>А как понимать "the declaration depends on a user-defined name of external linkage"?

B>Можно добавлять только специализации, зависящие от определенных пользователем типов.

А>>Можно маленький примерчик?


B>
B>struct test{};//определенный пользователем тип

B>namespace std
B>{
B>template<>
B>struct equal_to<test>{/**/};//Можно, ибо test -  определенный пользователем тип.

B>template<>
B>struct equal_to<const wchar_t*>{/**/};//Нельзя, ибо wchar_t - встроенный тип.
B>}
B>


Но LPCSTR тоже пользовательский тип, но он не имеет external linkage, так?
А как определить какой linkage имеет, к примеру struct test из Вашего примера?
Re[5]: специализация std::equal_to<>
От: igna Россия  
Дата: 31.08.07 07:15
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Но LPCSTR тоже пользовательский тип, ...


LPCSTR это не тип, это синоним типа, причем непользовательского.
Re[5]: специализация std::equal_to<>
От: Bell Россия  
Дата: 31.08.07 07:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Но LPCSTR тоже пользовательский тип, но он не имеет external linkage, так?

Нет, это алиас встроенного типа, полученный с помощью typedef — посмотри например в MSDN.

А>А как определить какой linkage имеет, к примеру struct test из Вашего примера?

Применительно к типам: Все типы за исключением локальных классов имеют external linkage.

3.5/2
A name is said to have linkage when it might denote the same object, reference, function, type, template,
namespace or value as a name introduced by a declaration in another scope:
— When a name has external linkage, the entity it denotes can be referred to by names from scopes of
other translation units or from other scopes of the same translation unit.
— When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in
the same translation unit.
— When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.

Любите книгу — источник знаний (с) М.Горький
Re[7]: специализация std::equal_to<>
От: Аноним  
Дата: 31.08.07 07:38
Оценка:
Здравствуйте, igna, Вы писали:

I>>Для const LPCSTR выберется та же твоя перегруженная что и для LPCSTR.


I>Ты же не объявляешь в дополнение к void f(int) еще и void f(const int). Собственно тут тебе и компилятор не позволит, как впрочем не позволил и в твоем случае.


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

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);
}
Re[8]: специализация std::equal_to<>
От: igna Россия  
Дата: 31.08.07 08:03
Оценка:
Здравствуйте, Аноним, Вы писали:

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


А>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);
А>}


Ну а лишний const тебе тут помог? Куда ты его вставил, чтоб поехало как хочется?

P.S. typedef не определяет нового типа.
Re[6]: специализация std::equal_to<>
От: Аноним  
Дата: 31.08.07 08:05
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Аноним, Вы писали:


А>>Но LPCSTR тоже пользовательский тип, но он не имеет external linkage, так?

B>Нет, это алиас встроенного типа, полученный с помощью typedef — посмотри например в MSDN.

А>>А как определить какой linkage имеет, к примеру struct test из Вашего примера?

B>Применительно к типам: Все типы за исключением локальных классов имеют external linkage.

B>

B>3.5/2
B>A name is said to have linkage when it might denote the same object, reference, function, type, template,
B>namespace or value as a name introduced by a declaration in another scope:
B>— When a name has external linkage, the entity it denotes can be referred to by names from scopes of
B>other translation units or from other scopes of the same translation unit.
B>— When a name has internal linkage, the entity it denotes can be referred to by names from other scopes in
B>the same translation unit.
B>— When a name has no linkage, the entity it denotes cannot be referred to by names from other scopes.


Большое спасибо. Немного разобрался
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.