请考虑以下用于计算两个值之间的绝对差值的示例。
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/