如何在约束中使用 ADL?
How to use ADL in Constraints?
举个例子,我想使用约束来确保函数isinf
是针对模板参数T
实现的。如果T
是float
、double
、long 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;
子句移动到全局命名空间。但这将 isinf
引入全局命名空间,我想避免这种情况。
将带有概念定义的using std::isinf;
子句封装在名为ABC
的命名空间中,然后直接在命名空间后添加using ABC::Test;
。这似乎有点奇怪。
有没有更好的解决方案?
这应该有效。我对 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
概念的具体规定。
举个例子,我想使用约束来确保函数isinf
是针对模板参数T
实现的。如果T
是float
、double
、long 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;
子句移动到全局命名空间。但这将isinf
引入全局命名空间,我想避免这种情况。将带有概念定义的
using std::isinf;
子句封装在名为ABC
的命名空间中,然后直接在命名空间后添加using ABC::Test;
。这似乎有点奇怪。
有没有更好的解决方案?
这应该有效。我对 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
概念的具体规定。