如何在约束中使用 ADL?

8 c++ argument-dependent-lookup c++-concepts c++20

例如,我想使用约束来确保isinf为模板参数实现该函数T。如果T是一floatdoublelong double或一体式,这可以通过以下方式进行:

#include <cmath>

template <typename T>
concept Test = requires (T a) {
    std::isinf(a);
};
Run Code Online (Sandbox Code Playgroud)

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

#include <cmath>

template <typename T>
concept Test = requires (T a) {
    using std::isinf;
    isinf(a);
};
Run Code Online (Sandbox Code Playgroud)

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

我看到了这个问题的两种解决方法:

  • using std::isinf;子句移动到全局命名空间。但这引入isinf了我想避免的全局命名空间。

  • using std::isinf;带有概念定义的子句封装在名为 的命名空间中ABC,然后using ABC::Test;直接添加到命名空间之后。这似乎有点奇怪。

有更好的解决方案吗?

Bar*_*rry 2

此类事情在范围中的工作方式是通过创建自定义点对象。这与您的第二个选项非常相似(我们在自定义命名空间中粘贴了 using 声明),除了我们还提供了一种机制,让用户可以调用正确的方法,而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{};
}
Run Code Online (Sandbox Code Playgroud)

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

template <typename T> 
concept Test = requires (T t) {
    N::isinf(t);
}
Run Code Online (Sandbox Code Playgroud)

这正是这个概念的具体range定义方式。

  • @Mestkon它为您提供了一个对象“N::isinf”,您可以使用它来进行调度。由于它是一个对象,因此您可以执行诸如将其传递到算法之类的操作......就像 `ranges::any_of(r, N::isinf)` 一样有效。 (2认同)