要求存在精确函数签名的 C++20 概念

标签 c++ c++20 c++-concepts

请考虑以下用于计算两个值之间的绝对差值的示例。

template<class T>
auto abs_diff(const T _a, const T _b) {
    return (_a > _b) ? (_a - _b) : (_b - _a);
}

对于某些内置类型 std::abs提供卓越的性能,所以如果std::abs(T x)存在我想使用它(假设我们对整数情况下的不同下溢/溢出行为不感兴趣)。为此我尝试添加如下约束模板函数

template<class T> requires requires (T x) { std::abs(x); }
auto abs_diff(const T _a, const T _b) {
    return std::abs(_a - _b);
}

现在 std::abs 的所有类型exists 将使用这个专门的版本。然而,所有隐式转换到这种类型的类型都会使用它,这是不受欢迎的。所以我的问题是:有没有办法要求概念中存在具有精确签名的函数(即 std::abs(T x) 的存在,而不仅仅是 std::abs(x) 编译的事实)。

注意:上面的例子主要是为了说明,至少对于我的应用程序,可以通过使用 requires (T x) { { std::abs(x) } -> std::same_as<T>; } 限制返回类型来修复。 .但是,我对此类问题的通用解决方案很感兴趣。

最佳答案

我们可以测试重载函数地址表达式是否为&std::abs可以转换为指向具有所需签名的函数的指针。或者我们可以,除了 C++20 不允许形成指向大多数标准库函数的指针。

在这里留下这个原始答案以供引用。对于不在标准库中的重载函数名称,这将是一个有效模式。无论如何它通常都可以工作,但我们不应该指望它继续使用更新的库版本。

#include <cmath>

template<class T>
auto abs_diff(const T _a, const T _b) {
    return (_a > _b) ? (_a - _b) : (_b - _a);
}

template<class T> requires requires (T (*fp)(T)) { fp = &std::abs; }
auto abs_diff(const T _a, const T _b) {
    return std::abs(_a - _b);
}

查看 test on godbolt .

当此技术用于包含匹配函数模板的名称时,如果没有非模板函数是完全匹配的,则也可以满足约束条件,但是一个最专业的函数模板可以推导其参数,以便一个专业就是T(T) .

(在 std::abs 中声明了一个 <complex> 函数模板,但它永远不能完全匹配类型 T(T) 。)

关于要求存在精确函数签名的 C++20 概念,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64146257/

相关文章:

c++ - VC++6中的MSXML问题

c++ - 动态调用 DLL C++

c++ - 为什么不将 [[nodiscard]] 应用于每个构造函数?

c++ - 如果没有提供 Container::value_type,如何获取 C++ Container<T> 的 T?

c++ - 使用 C++20 概念实现 Pair 概念

c++ - 从 vector 中删除一对并为 vector 对保留空间

c++ - 32 位和 64 位 Windows 上 GSL 库的差异导致 R 包错误?

c++ - Boost.ASIO 如何将链与 c++20 协程一起使用

c++ - 将具有动态范围的 std::span 转换为具有静态范围的 std::span

c++ - 如何为 unordered_map 定义一个检测其删除功能的概念