如何编写启用ADL的追踪返回types或noexcept规范?
想象一下,我正在写一些容器模板什么的。 而现在是专门为它的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); }
这非常整齐。 直到我想添加一个exception规范。 只要T
swap
被noexcept
,我的swap
就是noexcept
noexcept
。 所以,我会写这样的:
template <typename T> void swap(my_template<T>& x, my_template<T>& y) noexcept(noexcept(swap(std::declval<T>(), std::declval<T>())))
问题是,在那里swap
需要ADL发现swap
或std::swap
。 我该如何处理?
我想我会把它移动到一个单独的命名空间
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
并委派给那里。
返回types有一个类似的问题 :
// 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
不在范围内。
可能的解决方法是:
-
在封闭范围内引入一个虚拟模板(在我的例子中,
swap
你的情况) 这包括将using std::swap
声明放在封闭的名称空间中,其缺点是污染了名称空间。 -
在我的例子中,使用了一个types特征:
typename std::tuple_element<0, typename std::remove_reference<Tuple>::type>::type
(实际上这个是有问题的,但是不属于这里的原因)一个潜在的is_nothrow_swappable<T>::value
在你的情况。 然后专业化可以让模板扩展到其他types,如果需要的话。
而不是声明但不定义一个似乎可能导致混淆的函数模板,我会写我自己的types特征(无论如何,这应该是标准库中的东西)。 在标准库的引导下,我将定义如下的内容:
#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导入(以避免将其分发给每个人),但是当然,如果它在标准库中,则不必要,因为它们已经可以进行非限定的调用交换。
C ++ 17已经用std :: is_nothrow_swappable解决了这个特殊的用例: http ://en.cppreference.com/w/cpp/types/is_swappable