3

これが私のケースです:

Foo::atype を持ち、 a も指定するライブラリを使用しようとしてFoo::swapいます。私が使用している別のライブラリにはstd::vector<Foo::a>インスタンス化があります。Visual Studio 11.0 を使用して Windows でこれをコンパイルしようとしていますが、修飾されていないスワップ呼び出しを行うstd::vector::swapマップがダウンしていることに気付きました。_Swap_adl

これが、ADL とあいまいな関数の解決に関する問題に私を陥れるものです。Foo::swap私が消費しているライブラリに「大きな」変更を加えることなく(std::swapFooなどからスワップを削除/名前変更するだけのもの)、使用できるようにする魔法はありますか?

編集:何が起こっているのかとエラーをキャプチャする最小限の例を追加します。

#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より悪い代替案になるため、あいまいさはありません。


これにより、swap の名前が変更されることは回避されますが、その定義はわずかに変更されます。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適用できるの 2 つのバージョンがあります。1 つは namespaceFooで、もう 1 つは namespacestdです。1 つ目は、引数依存のルックアップによって検出されます。2 番目は、vectorで定義されstdているため、std::swap(設計どおり) が検出されます。

これは、ある宣言が別の宣言を隠す状況ではありません。これは単に可能なオーバーロードのセットであるため、オーバーロードされた関数を選択するための通常の順序規則が適用されます。の 2 つのバージョンはswap同じ引数の型を取るため、どちらが優先されるということはありません。

于 2013-03-23T11:40:13.307 に答える