例如,我想使用一个约束来确保为模板参数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根本不是“要求”。
我看到两个解决此问题的方法:
  • using std::isinf;子句移到全局 namespace 。但这将isinf引入了全局命名空间,我想避免这种情况。
  • 用概念定义将using std::isinf;子句封装在名为ABC的 namespace 中,然后在该 namespace 之后直接添加using ABC::Test;。这似乎有点不可思议。

  • 有更好的解决方案吗?

    最佳答案

    这种事情在Ranges中的工作方式是创建一个Customization Point Object。这紧密地反射(reflect)了您的第二个选项(我们在自定义 namespace 中粘贴了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{};
    }
    
    现在我们有了一个对象,直接遵循一个概念:
    template <typename T>
    concept Test = requires (T t) {
        N::isinf(t);
    }
    
    这就是 range 概念的确切指定方式。

    10-08 09:17