В чем ошибка?
От: DrMom  
Дата: 28.01.13 13:59
Оценка: 1 (1) -1
Всем привет.

Что-то я туплю с простым, как мне казалось, кодом:
#include <string>
#include <functional>
#include <boost/ref.hpp>

typedef boost::reference_wrapper<std::string> RefS;

template <class _Tp>
struct MyEqual : public std::binary_function<_Tp, _Tp, bool> 
{
   bool operator()(const _Tp& __x, const _Tp& __y) const 
   {
      return __x == __y; 
   }
};

int main() 
{
   std::string str;
   RefS ref1(str);
   {
      MyEqual<RefS> eq;
      eq(ref1, ref1);
   }
   {
      std::equal_to<RefS> eq;
//убираю коментарий и получаю ошибку. 
//      eq(ref1, ref1);
   }

   return 0;
}

bool operator==(const RefT& a, const RefT& b)
{
   return a==b;
}


Может кто поможет?
Re: В чем ошибка?
От: Abyx Россия  
Дата: 28.01.13 14:07
Оценка:
Здравствуйте, DrMom, Вы писали:

DM>_Tp

DM>__x
это UB.
In Zen We Trust
Re: В чем ошибка?
От: Abyx Россия  
Дата: 28.01.13 14:11
Оценка:
Здравствуйте, DrMom, Вы писали:

DM>//убираю коментарий и получаю ошибку.

DM>// eq(ref1, ref1);

это шутка такая -- "В чем ошибка?"
текст ошибки сюда напиши, а еще лучше F1 нажми
In Zen We Trust
Re: В чем ошибка?
От: DrMom  
Дата: 28.01.13 14:19
Оценка:
Здравствуйте, DrMom, Вы писали:


#include <string>
#include <functional>
#include <boost/ref.hpp>

typedef boost::reference_wrapper<std::string> RefS;

template <class _Tp>
struct MyEqual : public std::binary_function<_Tp, _Tp, bool> 
{
   bool operator()(const _Tp& __x, const _Tp& __y) const 
   {
      return __x == __y; 
   }
};

int main() 
{
   std::string str;
   RefS ref1(str);
   {
      MyEqual<RefS> eq;
      eq(ref1, ref1);
   }
   {
      std::equal_to<RefS> eq;
      eq(ref1, ref1);
   }

   return 0;
}

bool operator==(const RefS& a, const RefS& b)
{
   return a==b;
}
Re[2]: В чем ошибка?
От: DrMom  
Дата: 28.01.13 14:21
Оценка:
Здравствуйте, Abyx, Вы писали:

Да я могу и текст ошибки написать, мне не сложно.

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


DM>>//убираю коментарий и получаю ошибку.

DM>>// eq(ref1, ref1);

A>это шутка такая -- "В чем ошибка?"

A>текст ошибки сюда напиши, а еще лучше F1 нажми

c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string(90) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(109) : while compiling class template member function 'bool std::equal_to<_Ty>::operator ()(const _Ty &,const _Ty &) const'
with
[
_Ty=RefS
]
..\..\PerformanceTest\main.cc(25) : see reference to class template instantiation 'std::equal_to<_Ty>' being compiled
with
[
_Ty=RefS
]
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const _Elem *' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string(80) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::basic_string<_Elem,_Traits,_Alloc> &,const std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'const std::basic_string<_Elem,_Traits,_Alloc> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\string(70) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::istreambuf_iterator<_Elem,_Traits> &,const std::istreambuf_iterator<_Elem,_Traits> &)' : could not deduce template argument for 'const std::istreambuf_iterator<_Elem,_Traits> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\streambuf(548) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::allocator<_Ty> &,const std::allocator<_Other> &) throw()' : could not deduce template argument for 'const std::allocator<_Ty> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\xmemory(173) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\xutility(2246) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::_Revranit<_RanIt,_Base> &,const std::_Revranit<_RanIt2,_Base2> &)' : could not deduce template argument for 'const std::_Revranit<_RanIt,_Base> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\xutility(2050) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2784: 'bool std::operator ==(const std::pair<_Ty1,_Ty2> &,const std::pair<_Ty1,_Ty2> &)' : could not deduce template argument for 'const std::pair<_Ty1,_Ty2> &' from 'const RefS'
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\utility(83) : see declaration of 'std::operator =='
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include\functional(110) : error C2676: binary '==' : 'const RefS' does not define this operator or a conversion to a type acceptable to the predefined operator
Re: В чем ошибка?
От: zaufi Земля  
Дата: 28.01.13 14:30
Оценка: 2 (1)
Здравствуйте, DrMom, Вы писали:

DM>

DM>bool operator==(const RefT& a, const RefT& b)
DM>{
DM>   return a==b;
DM>}

DM>


вот этот операто просто не виден в глобальном пространстве имен... RefS это boost::reference wrapper из boost -- вот там и происходит поиск этого оператора...

ЗЫ: ну и понятное дело написан он у тя криво (и то что это скомпилится, если перенести), саапсем не значит что будет работать -- он у тя вызывает сам себя
Re[2]: В чем ошибка?
От: uzhas Ниоткуда  
Дата: 28.01.13 14:40
Оценка: :)
Здравствуйте, zaufi, Вы писали:

Z>вот этот операто просто не виден в глобальном пространстве имен... RefS это boost::reference wrapper из boost -- вот там и происходит поиск этого оператора...


пытаюсь понять как же оно там работает
пример 1 (компилируется): http://liveworkspace.org/code/1PSZtL$32
пример 2 (не компилируется): http://liveworkspace.org/code/1PSZtL$33
почему второй пример не собирается? ведь я воспроизвел реализацию std::equal_to в своем MyStd::MyEqual
Re[2]: Задача скомпилировать.
От: DrMom  
Дата: 28.01.13 14:44
Оценка:
Здравствуйте, zaufi, Вы писали:

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


DM>>

DM>>bool operator==(const RefT& a, const RefT& b)
DM>>{
DM>>   return a==b;
DM>>}

DM>>


Z>вот этот операто просто не виден в глобальном пространстве имен... RefS это boost::reference wrapper из boost -- вот там и происходит поиск этого оператора...

Этого не понял. Можно поподробнее?
Z>ЗЫ: ну и понятное дело написан он у тя криво (и то что это скомпилится, если перенести), саапсем не значит что будет работать -- он у тя вызывает сам себя

Пардон за кривой пример. Я его прям здесь писал.

Упрощения:


#include <string>
#include <functional>
#include <boost/ref.hpp>

using namespace boost;

typedef boost::reference_wrapper<std::string> RefS;

template <class _Tp>
struct MyEqual : public std::binary_function<_Tp, _Tp, bool> 
{
   bool operator()(const _Tp& __x, const _Tp& __y) const 
   {
      return __x == __y; 
   }
};

int main() 
{
   std::string str;
   RefS ref1(str);
   {
      MyEqual<RefS> eq;
      eq(ref1, ref1);
   }
   {
      std::equal_to<RefS> eq;
      eq(ref1, ref1);
   }

   return 0;
}

bool operator==(const RefS& a, const RefS& b)
{
   return false;
}
Re[3]: В чем ошибка?
От: DrMom  
Дата: 28.01.13 14:47
Оценка:
Здравствуйте, uzhas, Вы писали:

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


Z>>вот этот операто просто не виден в глобальном пространстве имен... RefS это boost::reference wrapper из boost -- вот там и происходит поиск этого оператора...


U>пытаюсь понять как же оно там работает

U>пример 1 (компилируется): http://liveworkspace.org/code/1PSZtL$32
U>пример 2 (не компилируется): http://liveworkspace.org/code/1PSZtL$33
U>почему второй пример не собирается? ведь я воспроизвел реализацию std::equal_to в своем MyStd::MyEqual

Спасибо за корректировки.
ЗЫ Надо ссылочки прикопать. Удобно.
Re: В чем ошибка?
От: zaufi Земля  
Дата: 28.01.13 17:27
Оценка:
в общем вот какая получается картина:

для начала пришлось обратиться к классикам: "C++ Templates: The Complete Guide" by David Vandevoorde, Nicolai M. Josuttis.

при парсе шаблонов, на первом этапе производится обычный поиск функций не зависящих от шаблонных параметров, а также, по возможности ADL для оных.
зависимые же функции ищутся подобным образом, затем составляется их список и запоминается до момента инстанциирования. в точке инстанциирования выполняется поиск для qualified имен с подставленными фактическими параметрами, и выполняется ADL для nonqualified имен (наколлекченых на первой фазе).

чтобы избавиться от лишних зависимостей (boost) я минимизировал пример до вот такого:

#include <functional>

#ifdef BEFORE
namespace zzz {
struct test {};
#ifdef INSIDE_NS
inline bool operator==(const test& a, const test& b)
{
    return false;
}
#endif                                                      // INSIDE_NS
}                                                           // namespace zzz
#ifdef OUTSIDE_NS
inline bool operator==(const zzz::test& a, const zzz::test& b)
{
    return false;
}
#endif                                                      // OUTSIDE_NS
#endif                                                      // BEFORE

namespace my {
template <class _Tp>
struct MyEqual : public std::binary_function<_Tp, _Tp, bool>
{
    bool operator()(const _Tp& __x, const _Tp& __y) const
    {
        return __x == __y;
    }
};
}                                                           // namespace my

#ifdef AFTER
namespace zzz {
struct test {};
#ifdef INSIDE_NS
inline bool operator==(const test& a, const test& b)
{
    return false;
}
#endif                                                      // INSIDE_NS
}                                                           // namespace zzz
#ifdef OUTSIDE_NS
inline bool operator==(const zzz::test& a, const zzz::test& b)
{
    return false;
}
#endif                                                      // OUTSIDE_NS
#endif                                                      // AFTER

int main()
{
    zzz::test t;
    {
        my::MyEqual<zzz::test> eq;
        eq(t, t);
    }
    {
        std::equal_to<zzz::test> eq;
        eq(t, t);
    }

    return 0;
}


дефайнами при компиляции рулится следующее:
  • BEFORE/AFTER -- определять тестовую структурку test в пространстве имен zzz ДО/ПОСЛЕ определения MyEqual (в пространстве имен my)
  • INSIDE_NS/OUTSIDE_NS -- определять operator== для zzz::test внутри/снаружи zzz

    и вот какие получаются результаты:
    zaufi@gentop /work/tests $ g++ -DAFTER -DOUTSIDE_NS -o refstr refstr.cc 
    zaufi@gentop /work/tests $ g++ -DAFTER -DINSIDE_NS -o refstr refstr.cc 
    zaufi@gentop /work/tests $ g++ -DBEFORE -DINSIDE_NS -o refstr refstr.cc 
    zaufi@gentop /work/tests $ g++ -DBEFORE -DOUTSIDE_NS -o refstr refstr.cc


    gcc 4.7.2 каким-то образом ухитрился скомпилячить все во всех случаях успешно -- вот этого я не понимаю... может надо багзилу ихнюю пошерстить...

    zaufi@gentop /work/tests $ clang++ -DBEFORE -DINSIDE_NS -o refstr refstr.cc 
    zaufi@gentop /work/tests $ clang++ -DBEFORE -DOUTSIDE_NS -o refstr refstr.cc 
    In file included from refstr.cc:1:
    In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/include/g++-v4/functional:49:
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/include/g++-v4/bits/stl_function.h:210:20: error: call to function 'operator==' that is neither visible in the
          template definition nor found by argument-dependent lookup
          { return __x == __y; }
                       ^
    refstr.cc:66:11: note: in instantiation of member function 'std::equal_to<zzz::test>::operator()' requested here
            eq(t, t);
              ^
    refstr.cc:19:13: note: 'operator==' should be declared prior to the call site or in namespace 'zzz'
    inline bool operator==(const zzz::test& a, const zzz::test& b)
                ^
    1 error generated.
    zaufi@gentop /work/tests $ clang++ -DAFTER -DINSIDE_NS -o refstr refstr.cc 
    zaufi@gentop /work/tests $ clang++ -DAFTER -DOUTSIDE_NS -o refstr refstr.cc 
    refstr.cc:33:20: error: call to function 'operator==' that is neither visible in the template definition nor found by argument-dependent lookup
            return __x == __y;
                       ^
    refstr.cc:62:11: note: in instantiation of member function 'my::MyEqual<zzz::test>::operator()' requested here
            eq(t, t);
              ^
    refstr.cc:50:13: note: 'operator==' should be declared prior to the call site or in namespace 'zzz'
    inline bool operator==(const zzz::test& a, const zzz::test& b)
                ^
    In file included from refstr.cc:1:
    In file included from /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/include/g++-v4/functional:49:
    /usr/lib/gcc/x86_64-pc-linux-gnu/4.7.2/include/g++-v4/bits/stl_function.h:210:20: error: call to function 'operator==' that is neither visible in the
          template definition nor found by argument-dependent lookup
          { return __x == __y; }
                       ^
    refstr.cc:66:11: note: in instantiation of member function 'std::equal_to<zzz::test>::operator()' requested here
            eq(t, t);
              ^
    refstr.cc:50:13: note: 'operator==' should be declared prior to the call site or in namespace 'zzz'
    inline bool operator==(const zzz::test& a, const zzz::test& b)
                ^
    2 errors generated.


    clang 3.2 повел себя как и положенно(?) по книжке: operator== это очевидно зависимое имя, значит на втором этапе выполняется только ADL при поиске.
    соответственно без разницы где находится определение zzz::test, до или после, определения my::MyEqual/std::equal_to, главное чтобы определение operator== для zzz::test находилось внутри пространства имен zzz. Либо, operator== может находится вне zzz, но он должен быть виден _до_ определения шаблона компаратора (о чем недвусмыленно пишет clang при компиляции с -DBEFORE -DOUTSIDE_NS: ошибка, естественно, только у std::equal_to, т.к. от за#includeн в начале файла

    вот теперь думаю кто из них прав: gcc или clang... clang вроде все прально делает, но не оставляет мысль что это таки в нем какаянить бага (ибо молод еще)...
    с другой стороны, gcc, по моим внутренним ощущениям должен быть менее глючным в поддержке С++03, но то что он все удачно собрал во всех вариантах, хотя казалось бы не должен, наводит на мысль что либо разработчики знают что-то чего я не допонимаю (вероятность чего конечно же высока), либо, что тоже известно, gcc сам "не без греха" (его базгилла также полна багов, правда как мне кажется, таких концептуальных как у clang у него поменьше будет)

    any ideas?
  •  
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.