Ненавязчивый способ обойти неопределенность поиска в зависимости от аргумента

Вот мой случай:

Я пытаюсь использовать библиотеку, которая имеет тип Foo::aи указывает Foo::swap также. Другая библиотека, которую я потребляю, имеет std::vector<Foo::a> конкретизации. Я пытаюсь скомпилировать это в Windows с помощью Visual Studio 11.0 и замечаю, что std::vector::swap карты вниз _Swap_adl который делает неквалифицированный вызов своп.

Это то, что приводит меня к проблемам с ADL и неоднозначным разрешением функций. Есть ли какая-то магия, которая позволит мне использовать Foo::swap (черт возьми, даже std::swap :)), без внесения каких-либо «существенных» изменений в библиотеки, которые я потребляю (что-то, кроме удаления / переименования свопа из Foo и т. д.)?

Редактировать:
Добавление минимального примера, который фиксирует происходящее и ошибку.

#include <iostream>
#include <vector>

namespace Foo
{
class MyType
{
public:
float dummy;
};

template <class T>
void swap(T& a, T& b)
{
T c(a);
a = b;
b = c;
}
}

using namespace Foo;

class MyClass
{
public:
std::vector<MyType> myStructArr;
};

std::vector<MyType> getMyTypeArray()
{
MyType myType;
std::vector<MyType> myTypeArray;
myTypeArray.push_back(myType);
return myTypeArray;
}

namespace std
{
template <>
void swap<MyType*>(MyType*& a, MyType*& b)
{
MyType* c(a);
a = b;
b = c;
}

template <>
void swap<MyType>(MyType& a, MyType& b)
{
MyType c(a);
a = b;
b = c;
}
}

int main(int argc, char* argv[])
{
MyClass m;

MyType myTypeLocal;
std::vector<MyType> myTypeArrayLocal;
myTypeArrayLocal.push_back(myTypeLocal);

//m.myStructArr = myTypeArrayLocal;
m.myStructArr = getMyTypeArray();

return 0;
}

Я не буду комментировать эффективность кода, так как это то, с чем мне просто нужно работать, но журнал ошибок на @ http://pastebin.com/Ztea46aC дает четкое представление о том, что происходит внутри. Это специфическая проблема компилятора, или есть более глубокий опыт, который можно извлечь из этого фрагмента кода?

Изменить 2:
Я пытался специализироваться для конкретного типа, о котором идет речь, но это не решает двусмысленность. Любые указатели на то, почему это так, также будут полезны.

namespace std
{
template <>
void swap<MyType*>(MyType*& a, MyType*& b)
{
MyType* c(a);
a = b;
b = c;
}

template <>
void swap<MyType>(MyType& a, MyType& b)
{
MyType c(a);
a = b;
b = c;
}
}

http://pastebin.com/sMGDZQBZ это журнал ошибок от этой попытки.

2

Решение

Как говорится в сообщении об ошибке, вызов функции неоднозначен. Есть две версии swap что может быть применено: один в пространстве имен Foo и тот, в пространстве имен std, Первый находится в зависимости от аргумента поиска. Второй найден потому что vector определяется в stdтак видит std::swap (как задумано).

Это не ситуация, когда одно объявление скрывает другое; это просто набор возможных перегрузок, поэтому применяются обычные правила упорядочения для выбора перегруженной функции. Две версии swap принимать те же типы аргументов, чтобы не было предпочтения одного над другим.

0

Другие решения

Ответ Пита объясняет ситуацию. Оба шаблона для подкачки одинаково предпочтительны на этапах разрешения перегрузки, поэтому вызов неоднозначен — в любой контекст, в котором видны оба пространства имен. Специализация — правильный подход к этой проблеме, однако, основываясь на своих ошибках, вы забыли удалить шаблон, вызвавший оскорбления. Foo::swap — увидеть Вот как должен выглядеть ваш код.

Вот как все выглядит — я просто заменил std пространство имен с bar Пространство имен.

#include <iostream>

namespace bar { //std namespace

template<typename T>
void swap(T s, T t){ std::cout << "bar swap\n"; }

template<typename S>
struct vec {
S s;
void error() { swap(s, s); }
};}

namespace foo { //your namespace

struct type {};

/*this template is not allowed/not a good idea because of exactly your problem
template<typename T>
void swap(T s, T t){ std::cout << "foo swap\n"; }
*/

//you will have to rename foo::swap to something like this, and make it call
//specialise std::swap for any types used in std containers, so that they called yuor
//renamed foo::swap
template<typename T>
void swap_proxy(T s, T t){ std::cout << "foo swap (via proxy) \n"; }

}

namespace bar {
template<> void swap(foo::type s, foo::type t) { std::cout << "foo swap\n"; }
}

int main()
{
//instead specialise std::swap with your type

bar::vec<foo::type> myVec;
myVec.error();

std::cout << "Test\n";
operator<<(std::cout, "Test\n");
}

Все, что сказал, я попытаюсь приготовить шаблонную альтернативу — однако это назовет std::swap в коде std (это сделает foo::swap худшая альтернатива, поэтому не будет никакой двусмысленности.


Это позволяет избежать изменения имени свопа, но все же немного меняет его определение — хотя
вам не нужно вмешиваться в код внутри свопинга, только код, который вызывает вызов, должен быть приведен, как объяснено

#include <iostream>

namespace bar { //std namespace

template<typename T>
void swap(T s, T t){ std::cout << "bar swap\n"; }

template<typename S>
struct vec {
S s;
void error() { swap(s, s); }
};}

namespace foo { //your namespace

// Include this pattern (The infamous Curiously Recurring Template Pattern) in foo namespace

template<template<class> class Derived, typename t>
struct Base : public t { Base(){} Base(Derived<t> d){} };

template<typename t> struct Derived : public Base<Derived, t> {};

template<class t> using UnWrapped = Base<Derived, t>;
template<class t> using Wrapped = Derived<t>;//we redefine swap to accept only unwrapped t's - meanwhile
//we use wrapped t's in std::containers
template<typename T>
void swap(UnWrapped<T> s, UnWrapped<T> t){ std::cout << "foo swap\n"; }

struct type {
};

}

int main()
{
//use the wrapped type
typedef foo::Wrapped<foo::type> WrappedType;
typedef foo::UnWrapped<foo::type> UnWrappedType;

bar::vec<WrappedType> myVec;
//this is the function which makes the ambiguous call
myVec.error();
//but instead calls bar::swap

//but -- it calls foo swap outside of bar! - any you didn't
//have to change the name of swap, only alter definition slightly
swap(WrappedType(), WrappedType());
//safe outside of bar
swap(UnWrappedType(), UnWrappedType());
//the following no longer works :/
//swap<foo::type>(foo::type(), foo::type());
//instead, yuo will have to cast to UnWrapped<type>
}
0

По вопросам рекламы [email protected]