1

を使用したいのですが、削除するのが難しいテンプレート化された関数が名前空間に定義されているためstd::sort、コンパイルがエラーで失敗します。どちらを使用するかは気にしませんが、コンパイル時にどちらかをなくすにはどうすればよいですか?C2668: std::swap: ambiguous call to overloaded functionswap()swapsort()

my::swapは と同じ名前空間にあるためあいまいであることは理解しています。どのバージョンのが使用されるmy::Objかは気にしません。swap名前空間の衝突を克服する必要があります。これは私が所有していない非常に大きなコード ベースの一部であるため、私のコードにローカルであり、おそらく名前空間にとどまるmy::Objことができるソリューションを望んでいます。my::swapmy

namespace my
{
    template<class T> void swap(T a, T b)
    {
    }

    struct Obj
    {
    };

    void doSortStuff()
    {
        std::vector<Obj> arr;
        std::sort(arr.begin(), arr.end());
    }
};
4

3 に答える 3

2

回避策は、より良いオーバーロードを作成することです。

// No modifiable code
namespace my
{
    template<class T> void swap(T a, T b) { /*.. */ }
    struct Obj { /*..*/ };
}

// Your code:
namespace my
{
    void swap(Obj& lhs, Obj& rhs)
    {
        // my::swap<Obj&>(lhs, rhs);
        std::swap(lhs, rhs);
    }
}

// In namespace you want.
void doSortStuff()
{
    std::vector<my::Obj> arr;
    std::sort(arr.begin(), arr.end());
}

次に、3 つの有効なオーバーロードの間で、すべてが完全に一致しますが、テンプレートが優先されます。

于 2018-10-26T00:09:22.210 に答える
2

一部のコメントとは対照的に、一部の人にとっては驚くべきことですが、このエラーは なしで発生しusing namespace stdます。何が起こっているのかを理解するための最小限の例を次に示します。

namespace like_std
{
    template<class T> void swap(T a, T b) {}

    template <class T> auto test(T x, T y)
    {
        swap(x, y); // (1) ambiguous call
    }
}

namespace my
{
    template<class T> void swap(T a, T b) {}

    struct Obj {};

    void doStuff()
    {
        like_std::test(Obj{}, Obj{});
    }
};

から関数への呼び出しを行い、like_stdこの関数内で への修飾されていない呼び出しがありswapます。この呼び出しの場合:

  • like_std::swapへの呼び出しと同じ名前空間にあるため、候補ですswap

  • my::swapは ADL のための候補です: の呼び出しの引数の 1 つと同じ名前空間にあるため、取り込まれますswap

どちらも優れていないため、あいまいさがあります。

swapへの呼び出しが修飾されていない理由は、カスタムswap定義されている場合はカスタムを取得するためですが、それは、カスタム関数として想定されているカスタムがより適切な候補である場合にのみ機能します。swapswap

Jarod42が示したように、解決策はより良い候補swap関数を定義することです。

于 2018-10-26T00:39:29.047 に答える