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的 isnoexcept只要交换为Tis noexcept。所以,我会写这样的东西:

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

问题是,swap其中需要发现 ADLswapstd::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 回答