Как побороть поиск Кенига?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 14:20
Оценка:
Здравствуйте, коллеги!

В начале приведу пример, похожий на мою ситуацию:

#include <vector>
#include <iostream>
#include <algorithm>


namespace my
{
    class A
    {
    };
 
    template<typename Something>
    void swap(Something &s1, Something &s2)
    {
        std::cout<<"::my::swap\n";
    }

    void myFunction( A** pa, size_t s )
    {
        std::cout<<"size"<<(unsigned)s<<"\n";
    }

    void myFunction( const ::std::vector< A* > &vec)
    {
        myFunction( const_cast< A** >(&vec[0]), (size_t)vec.size() );
    }
}


int main()
{
    ::std::vector< ::my::A* > v1, v2;
    //v1.push_back(0);
    //v2.push_back(0);
    //v2.push_back(0);

    ::my::myFunction(v1);
    ::my::myFunction(v2);

    //namespace my {
    //swap(v1,v2);

    //};

    //v1.swap(v2);
    //::std::swap(v1,v2);
    ::std::reverse(v1.begin(), v2.begin());    //v1.resize( 3, 0);

    
    ::my::myFunction(v1);
    ::my::myFunction(v2);
}


На выделенную строку студия 2008 ругается, что возникла неоднозначность между std::swap и my::swap в недрах stl.
С одной стороны все вроде бы правильно, но меня это не устраивает, потому, что в NS my я ввел для своих объектов специально, чтобы он не пересекался со стандартным. Можно специализировать std::swap, но я этого не делал, потому что не был уверен, какая версия swap будет вызыватся при использовании различных компиляторов, как довольно старых, так и новых (код работает с GCC от 3.3 до 4.4.1, msvc 2005, на 2008 не компилируется ). Имя swap выбрал для того, чтобы показать, что семантика соответствует std::swap, но работает для объектов из ::my, и когда необходимо, явно специфицировал вызов (::my::swap). Причем, подразумевалось, что если не указано ::my::swap, то должна работать версия std::swap
Как тут поступить?
Маньяк Робокряк колесит по городу
Re: Пример кода
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 14:21
Оценка:
Здравствуйте, Marty, Вы писали:

Иллюстрации.
Мой swap такой:

namespace cli {
template <class IFWrapper> inline
void swap( IFWrapper &w1, IFWrapper &w2 )
   {
    typename IFWrapper::interface_pointer_type* p1 = w1.getPP();
    typename IFWrapper::interface_pointer_type* p2 = w2.getPP();
    CLIASSERT(p1 && p2);
    typename IFWrapper::interface_pointer_type tmp = w1.getIfPtr();
    *p1 = w2.getIfPtr();
    *p2 = tmp;
   }
};


Объекты, для которых он предназначен (их много, и они не связаны ни в какую иерархию)
    namespace cli {
        // interface ::cli::iAllocator wrapper
        template <
                  typename smartPtrType
                 >
        class CiAllocatorWrapper
        {
            public:
        
                typedef  CiAllocatorWrapper< smartPtrType >           wrapper_type;
                typedef  typename smartPtrType::interface_type              interface_type;
                typedef  typename smartPtrType::interface_pointer_type      interface_pointer_type;
                typedef  typename smartPtrType::pointer_type                pointer_type;
        
            protected:
        
                smartPtrType                pif;
        
            public:
        
                CiAllocatorWrapper() :
                   pif(0) {}
        
                CiAllocatorWrapper( iAllocator *_pi, bool noAddRef=false) :
                   pif(_pi, noAddRef)
                  { }
        
                operator bool() const { return bool(pif); }
                bool operator!() const { return pif.operator!(); }
                interface_pointer_type* getPP() { return pif.getPP(); }
        
                interface_pointer_type getIfPtr()
                   {
                    interface_pointer_type* ptrPtr = pif.getPP();
                    if (!ptrPtr) return 0;
                    return *ptrPtr;
                   }
        
                void release()
                   {
                    pif.release();
                   }
        
                CiAllocatorWrapper( const CHAR *componentId, INTERFACE_CLI_IUNKNOWN *pOuter=0) :
                   pif(0)
                  {
                   RCODE res = pif.createObject( componentId, pOuter );
                   if (RC_FAIL(res))
                      throw ::std::runtime_error("Failed to create requiested component");
                  }
        
                CiAllocatorWrapper( const ::std::string &componentId, INTERFACE_CLI_IUNKNOWN *pOuter=0) :
                   pif(0)
                  {
                   if (componentId.empty())
                      throw ::std::runtime_error("Empty component name taken");
                   RCODE res = pif.createObject( componentId.c_str(), pOuter );
                   if (RC_FAIL(res))
                      throw ::std::runtime_error("Failed to create requiested component");
                  }
        
               CiAllocatorWrapper( INTERFACE_CLI_IUNKNOWN *pUnk) :
                   pif(0)
                  {
                   ::cli::CFoolishPtr<INTERFACE_CLI_IUNKNOWN> tmpPtr(pUnk);
                   RCODE res = tmpPtr.queryInterface(pif);
                   if (RC_FAIL(res))
                      throw ::std::runtime_error("Requested interface not supported by object");
                  }
        
                CiAllocatorWrapper(const CiAllocatorWrapper &i) :
                    pif(i.pif) { }
        
                ~CiAllocatorWrapper()  { }
        
                CiAllocatorWrapper& operator=(const CiAllocatorWrapper &i)
                   {
                    if (&i!=this) pif = i.pif;
                    return *this;
                   }
        
                template <typename T>
                RCODE queryInterface( T **t)
                  {
                   return pif.queryInterface(t);
                  }
        
                template <typename T>
                RCODE queryInterface( T &t)
                  {
                   t.release();
                   return pif.queryInterface(t.getPP());
                  }
        
                RCODE create(CHAR const * componentId, INTERFACE_CLI_IUNKNOWN *pOuter=0)
                   {
                    return pif.createObject(componentId, pOuter);
                   }
        
                VOID* allocate( SIZE_T    blockSize /* [in] size_t  blockSize  */
                              , UINT    flags /* [in] uint  flags  */
                              , BYTE    bFill /* [in] byte  bFill  */
                              )
                   {
                    return pif->allocate(blockSize, flags, bFill);
                   }
                
                VOID* reallocate( const VOID*    pMem /* [in] void*  pMem  */
                                , SIZE_T    newBlockSize /* [in] size_t  newBlockSize  */
                                , UINT    flags /* [in] uint  flags  */
                                , BYTE    bFill /* [in] byte  bFill  */
                                )
                   {
                    return pif->reallocate(pMem, newBlockSize, flags, bFill);
                   }
                
                RCODE deallocate( const VOID*    pMem /* [in] void*  pMem  */)
                   {
                
                    return pif->deallocate(pMem);
                   }
                
        }; // class CiAllocatorWrapper
        
        typedef CiAllocatorWrapper< ::cli::CCliPtr< INTERFACE_CLI_IALLOCATOR     > >  CiAllocator;
        typedef CiAllocatorWrapper< ::cli::CFoolishPtr< INTERFACE_CLI_IALLOCATOR > >  CiAllocator_nrc; /* No ref counting for interface used */
        typedef CiAllocatorWrapper< ::cli::CFoolishPtr< INTERFACE_CLI_IALLOCATOR > >  CiAllocator_tmp; /* for temporary usage, same as CiAllocator_nrc */
    }; // namespace cli
Маньяк Робокряк колесит по городу
Re: И вопрос по сообщению об ошибке
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 14:27
Оценка:
Здравствуйте, Marty, Вы писали:

Почему, хотя шаблоны практически одинаковы (в std::swap используется class вместо typename и шаблон объявлен inline, попробовал поменять свой также — ни чего не поменялось в сообщении) они выводятся компилятором по разному (в моем варианте — как будто два аргумента у шаблона)?

cli::util::swap<_Ty>(IFWrapper &,IFWrapper &)
void std::swap<_Ty>(_Ty &,_Ty &)


Вот так выглядит полное сообщение об ошибке:

4>c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(31) : error C2668: 'std::swap' : ambiguous call to overloaded function
4> f:\work\navis\trunk\include\cli\cliutilx.h(994): could be 'void cli::util::swap<_Ty>(IFWrapper &,IFWrapper &)' [found using argument-dependent lookup]
4> with
4> [
4> _Ty=cli::iErrorInfo *,
4> IFWrapper=cli::iErrorInfo *
4> ]
4> c:\program files (x86)\microsoft visual studio 9.0\vc\include\utility(16): or 'void std::swap<_Ty>(_Ty &,_Ty &)'
4> with
4> [
4> _Ty=cli::iErrorInfo *
4> ]
4> while trying to match the argument list '(cli::iErrorInfo *, cli::iErrorInfo *)'


cli::util::swap<_Ty>(IFWrapper &,IFWrapper &)
void std::swap<_Ty>(_Ty &,_Ty &)
Маньяк Робокряк колесит по городу
Re: Как побороть поиск Кенига?
От: breee breee  
Дата: 27.04.11 14:44
Оценка:
Здравствуйте, Marty, Вы писали:

M>Как тут поступить?


Например, создать в my вложенное пространство имен и переместить swap туда.
Re: Как побороть поиск Кенига?
От: uzhas Ниоткуда  
Дата: 27.04.11 14:46
Оценка:
Здравствуйте, Marty, Вы писали:

M>На выделенную строку студия 2008 ругается, что возникла неоднозначность между std::swap и my::swap в недрах stl.

M>С одной стороны все вроде бы правильно, но меня это не устраивает, потому, что в NS my я ввел для своих объектов специально, ...
M>Как тут поступить?

откажитесь от шаблонов, например
http://ideone.com/sqSCA
либо другим методом сделайте ваш swap более специфичным, чтобы он имел приоритет перед std::swap
Re: Как побороть поиск Кенига?
От: rg45 СССР  
Дата: 27.04.11 14:46
Оценка: 4 (2)
Здравствуйте, Marty, Вы писали:

M> Здравствуйте, коллеги!

M>В начале приведу пример, похожий на мою ситуацию:
M>...

M>На выделенную строку студия 2008 ругается, что возникла неоднозначность между std::swap и my::swap в недрах stl.

M>С одной стороны все вроде бы правильно, но меня это не устраивает, потому, что в NS my я ввел для своих объектов специально, чтобы он не пересекался со стандартным. Можно специализировать std::swap, но я этого не делал, потому что не был уверен, какая версия swap будет вызыватся при использовании различных компиляторов, как довольно старых, так и новых (код работает с GCC от 3.3 до 4.4.1, msvc 2005, на 2008 не компилируется ). Имя swap выбрал для того, чтобы показать, что семантика соответствует std::swap, но работает для объектов из ::my, и когда необходимо, явно специфицировал вызов (::my::swap). Причем, подразумевалось, что если не указано ::my::swap, то должна работать версия std::swap
M>Как тут поступить?

Все очень просто: внутри std::reverse есть обращение к swap с фактическими параметрами типа A&. Поиск подходящей кандидатуры на подстановку выполняется не только в окружающих пространствах имен, но и в пространстве имен фактических параметров. Вот и возникает неоднозначность. Победить легко — достаточно вынести определение класса A в отдельное пространство имен. А чтоб удобно было пользоваться и не пришлось изменять уже существующий код, можно воспользоваться объявлением using:

#include <vector>
#include <iostream>
#include <algorithm>

namespace my {
namespace detail {

class A
{
};

} //namespace detail

using detail::A; 

template<typename Something>
void swap(Something &s1, Something &s2)
{
  std::cout<<"::my::swap\n";
}

} //namespace my

int main()
{
  ::std::vector< ::my::A* > v1, v2;
  ::std::reverse(v1.begin(), v2.begin());
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: Как побороть поиск Кенига?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 14:55
Оценка:
Здравствуйте, breee breee, Вы писали:

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


M>>Как тут поступить?


BB>Например, создать в my вложенное пространство имен и переместить swap туда.


Ну у меня примерно так и сделано:
namespace my{
namespace util{
// template swap goes here
}; // util
using util::swap;
}; // my

Хотелось записи покороче, и она проросла слегка по остальному коду
Маньяк Робокряк колесит по городу
Re[2]: Как побороть поиск Кенига?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 14:58
Оценка:
Здравствуйте, uzhas, Вы писали:

M>>Как тут поступить?


U>откажитесь от шаблонов, например

U>http://ideone.com/sqSCA
U>либо другим методом сделайте ваш swap более специфичным, чтобы он имел приоритет перед std::swap

Просто функция, перегруженная для каждого типа?
Для многих классов надо делать ;(
А какие еще методы можно использовать?
Маньяк Робокряк колесит по городу
Re[2]: Как побороть поиск Кенига?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 15:01
Оценка:
Здравствуйте, rg45, Вы писали:

R>Все очень просто: внутри std::reverse есть обращение к swap с фактическими параметрами типа A&. Поиск подходящей кандидатуры на подстановку выполняется не только в окружающих пространствах имен, но и в пространстве имен фактических параметров. Вот и возникает неоднозначность. Победить легко — достаточно вынести определение класса A в отдельное пространство имен. А чтоб удобно было пользоваться и не пришлось изменять уже существующий код, можно воспользоваться объявлением using:


Спасибо, идею понял. Много писанины, так же как и в этом
Автор: uzhas
Дата: 27.04.11
способе.

Пока самым оптимальным вижу этот
Автор: breee breee
Дата: 27.04.11
способ.

Хотелось бы найти максимально красивое решение
Маньяк Робокряк колесит по городу
Re[3]: Как побороть поиск Кенига?
От: rg45 СССР  
Дата: 27.04.11 15:04
Оценка:
Здравствуйте, Marty, Вы писали:

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


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


M>>>Как тут поступить?


BB>>Например, создать в my вложенное пространство имен и переместить swap туда.


M>Ну у меня примерно так и сделано:

M>namespace my{
M>namespace util{
M>// template swap goes here
M>}; // util
M>using util::swap;
M>}; // my

M>Хотелось записи покороче, и она проросла слегка по остальному коду


Ну так получается то же самое, только в профиль: при поиске подходящей кандидатуры на подстановку swap внутри std::reverse, она находится в пространстве имен my, благодаря объявлению using. Надо наоборот — swap оставить в my, а class A унести в util:
namespace my{
namespace util{
class A { /*...*/ };
}; // util
using util::A;
// template swap goes here
}; // my
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[3]: Как побороть поиск Кенига?
От: rg45 СССР  
Дата: 27.04.11 15:13
Оценка:
Здравствуйте, Marty, Вы писали:

R>>Все очень просто: внутри std::reverse есть обращение к swap с фактическими параметрами типа A&. Поиск подходящей кандидатуры на подстановку выполняется не только в окружающих пространствах имен, но и в пространстве имен фактических параметров. Вот и возникает неоднозначность. Победить легко — достаточно вынести определение класса A в отдельное пространство имен. А чтоб удобно было пользоваться и не пришлось изменять уже существующий код, можно воспользоваться объявлением using:


M>Спасибо, идею понял. Много писанины, так же как и в этом
Автор: uzhas
Дата: 27.04.11
способе.


M>Пока самым оптимальным вижу этот
Автор: breee breee
Дата: 27.04.11
способ.


M>Хотелось бы найти максимально красивое решение


Какой писанины? Наоборот, если ты класс A перемещаешь в пространство имен detail окружающий код вообще не меняется, благодаря объявлению using detail::A. А вот если ты в пространство имен detail уносишь swap, то объявлением using detail::swap ты уже воспользоваться не сможешь (потому, что получишь ту же самую ошибку), и везде в вызывающем коде тебе придется вместо my::swap писать my::detail::swap
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: Как побороть поиск Кенига?
От: Marty Пират https://www.youtube.com/channel/UChp5PpQ6T4-93HbNF-8vSYg
Дата: 27.04.11 16:13
Оценка:
Здравствуйте, rg45, Вы писали:

M>>Хотелось записи покороче, и она проросла слегка по остальному коду


R>Ну так получается то же самое, только в профиль: при поиске подходящей кандидатуры на подстановку swap внутри std::reverse, она находится в пространстве имен my, благодаря объявлению using. Надо наоборот — swap оставить в my, а class A унести в util:

R>
R>namespace my{
R>namespace util{
R>class A { /*...*/ };
R>}; // util
R>using util::A;
R>// template swap goes here
R>}; // my
R>


если закоментировать using util::swap, то все вроде компилируется.

Тут задумался, а какая версия swap работала раньше при использовании векторов? Похоже что стандартная, и даже странно, что вроде все нормально было. Хотя для обертки operator= перегружен, наверно поэтому. Надо разбиратся, зачем я придумал еще свой swap Выкинуть его вообще, что ли
Маньяк Робокряк колесит по городу
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.