这是我的情况:
我正在尝试使用类型为Foo::a
的库,并指定Foo::swap
。我正在使用的另一个库具有std::vector<Foo::a>
实例化。我正在尝试使用Visual Studio 11.0在Windows上编译它,并注意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 是此尝试的错误日志。
答案 0 :(得分:0)
如错误消息所示,函数调用不明确。可以应用swap
的两个版本:名称空间Foo
中的一个和名称空间std
中的一个版本。第一个是通过参数依赖查找找到的。找到第二个是因为vector
中定义了std
,所以看std::swap
(按照设计)。
这不是一个声明隐藏另一个声明的情况;它只是一组可能的重载,因此适用于选择重载函数的通常排序规则。 swap
的两个版本采用相同的参数类型,因此没有一个优先于另一个。
答案 1 :(得分:0)
皮特的回答解释了这种情况。在重载解析步骤中,交换的两个模板都同样受欢迎,因此调用是不明确的 - 在任何上下文中,两个命名空间都是可见的。专业化是解决此问题的正确方法,但根据您的错误,您忘记删除有问题的模板Foo::swap
- 请参阅here了解您的代码应该是什么样的。
以下是所有内容 - 我只是将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
(它会使foo::swap
成为更糟糕的替代方案,因此不存在歧义。< / p>
这可以避免更改交换名称,但仍然会略微更改其定义 - 尽管如此 你不应该篡改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>
}