如何在约束中使用 ADL?

How to use ADL in Constraints?

举个例子,我想使用约束来确保函数isinf 是针对模板参数T 实现的。如果Tfloatdoublelong double之一或整数类型,可以通过以下方式完成:

#include <cmath>

template <typename T>
concept Test = requires (T a) {
    std::isinf(a);
};

但是,我还想将此约束用于我实现自己的 isinf 函数的自定义非标准数据类型。此函数不包含在 std 命名空间中,因此我尝试了以下方法:

#include <cmath>

template <typename T>
concept Test = requires (T a) {
    using std::isinf;
    isinf(a);
};

这是行不通的,因为 require 子句中的每个语句都应该是有效的要求,而 using std::isinf 根本不是“要求”。

我看到这个问题有两个解决方法:

有没有更好的解决方案?

这应该有效。我对 c++20 的概念不是很满意,所以我不能保证语法是正确的。

namespace impl {

using std::isinf;
template<class T>
auto adl_isinf(T t) -> decltype(isinf(t));
// { return isinf(t); } // implementation not necessary depending on whether
                        // requires is an unevaluated context
}

template <typename T>
concept Test = requires (T a) {
    impl::adl_isinf(a);
};

这种事情在范围中的工作方式是创建自定义点对象。这与您的第二个选项非常相似(我们将 using-declaration 放在自定义命名空间中)除了我们还为用户提供了一种机制来调用正确的 isinf 而无需自己编写一堆相同类型的样板.

isinf 的自定义点对象看起来像这样:

namespace N {
    // make our own namespace
    namespace impl {
        // ... where we can bring in std::isinf
        using std::isinf;

        struct isinf_t {
            // our type is constrained on unqualified isinf working
            // in a context where std::isinf can be found
            template <typename T>
                requires requires (T t) {
                    { isinf(t) } -> std::same_as<bool>;
                }
            constexpr bool operator()(T t) const {
                // ... and just invokes that (we know it's valid and bool at this point)
                return isinf(t);
            }
        };
    }

    // we provide an object such that `isinf(x)` incorporates ADL itself
    inline constexpr auto isinf = impl::isinf_t{};
}

现在我们有了一个对象,下面直接就是一个概念:

template <typename T> 
concept Test = requires (T t) {
    N::isinf(t);
}

这正是 range 概念的具体规定。