46

コンテナテンプレートなどを書いていると想像してみてください。そして、それに特化する時が来ましstd::swapた。善良な市民として、私は次のようなことを行うことでADLを有効にします。

template <typename T>
void swap(my_template<T>& x, my_template<T>& y) {
    using std::swap;
    swap(x.something_that_is_a_T, y.something_that_is_a_T);
}

これは非常にきちんとしていて、すべてです。例外仕様を追加したいまで。swapのスワップがであるnoexcept限り、私のはTですnoexcept。だから、私は次のようなものを書いているでしょう:

template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
    noexcept(noexcept(swap(std::declval<T>(), std::declval<T>())))

問題は、 ADLで発見されたまたはswapである必要があるということです。これをどのように処理しますか?swapstd::swap

4

4 に答える 4

34

別の名前空間に移動すると思います

namespace tricks {
    using std::swap;

    template <typename T, typename U>
    void swap(T &t, U &u) noexcept(noexcept(swap(t, u)));
}

template <typename T>
void swap(my_template<T>& x, my_template<T>& y)
  noexcept(noexcept(tricks::swap(std::declval<T>(), std::declval<T>()))) 
{
    using std::swap;
    swap(x.something_that_is_a_T, y.something_that_is_a_T);
}

または、コード全体を上に移動して、tricksそこに委任することもできます。

于 2011-10-03T14:18:51.333 に答える
10

リターンタイプにも同様の問題があります。

// Want to be compatible with both boost::tuple and std::tuple
template<typename Tuple>
auto first(Tuple&& tuple)
-> /* ??? */
{
    // Introduce name into scope
    using std::get;
    // but ADL can still pick boost::get for boost::tuple
    return get<0>(std::forward<Tuple>(tuple));
}

スコープ内にないため、使用decltype( get<0>(std::forward<Tuple>(tuple)) )は正しくありません。get

考えられる回避策は次のとおりです。

  • 囲んでいるスコープにダミーテンプレート(get私の例でswapは、あなたの場合)を導入します。これにはusing std::swap、名前空間を汚染するという欠点がありますが、宣言を囲んでいる名前空間に配置することも含まれます。

  • タイプ特性の使用:(typename std::tuple_element<0, typename std::remove_reference<Tuple>::type>::type実際にはこれは問題がありますが、ここに属さない理由で)私の例では、そしてis_nothrow_swappable<T>::valueあなたの場合には可能性があります。特殊化により、必要に応じてテンプレートを他のタイプに拡張できます。

于 2011-10-03T14:11:04.377 に答える
5

混乱を引き起こす可能性が高い関数テンプレートを宣言するが定義しないのではなく、独自の型特性を記述します(とにかく、これはおそらく標準ライブラリにあるはずです)。標準ライブラリの先導に従って、私は次のようなものを定義します。

#include <type_traits>
#include <utility>

namespace adl {

using std::swap;

template<typename T, typename U>
struct is_nothrow_swappable : std::integral_constant<
    bool,
    noexcept(swap(std::declval<T &>(), std::declval<U &>()))
> {
};

}   // namespace adl

std :: swapをインポートするために独自の名前空間を定義する必要があります(すべての人に渡さないようにするため)が、もちろん、標準ライブラリにある場合は、スワップに対して非修飾の呼び出しを行うことができるため、必要ありません。

于 2013-12-07T00:38:17.387 に答える
1

C ++ 17は、std :: is_nothrow_swappableを使用してこの特定のユースケースを解決しました:http ://en.cppreference.com/w/cpp/types/is_swappable

于 2017-02-06T04:53:50.463 に答える