3

这是我的情况:

我正在尝试使用具有 typeFoo::a并指定 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是这次尝试的错误日志。

4

2 回答 2

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标准代码(这将是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>
}
于 2013-12-24T06:26:56.973 回答
0

正如错误消息所说,函数调用不明确。有两个版本swap可以应用:一个在 namespaceFoo中,一个在 namespace 中std。第一个是通过参数相关查找找到的。找到第二个是因为vector在 中定义std,所以看到std::swap(按设计)。

这不是一个声明隐藏另一个声明的情况。它只是一组可能的重载,因此适用于选择重载函数的常用排序规则。这两个版本swap采用相同的参数类型,因此没有一个优于另一个的偏好。

于 2013-03-23T11:40:13.307 回答