模板元编程消除有符号与无符号比较警告

问题描述 投票:0回答:1

前段时间,我想创建 Python 三元比较运算符 (

a <= b <= c
) 的等效项。在这篇文章中获得帮助后,我最终得到了一组函数:

// This helper determines if 'test' is in the range [low, high]
template<typename Low, typename Val, typename High>
bool between(Low const& low, Val const& test, High const& high);

// This helper determines if 'test' is in the range (low, high)
template<typename Low, typename Val, typename High>
bool within(Low const& low, Val const& test, High const& high);

// This helper determines if 'test' is in the range [low, high)
template<typename Low, typename Val, typename High>
bool contained(Low const& low, Val const& test, High const& high);

这些运行良好,并有各种单元测试来验证其性能。然而,最近我发现有人关闭了编译器警告,所以我重新打开它们,并在其中一个函数上收到了无符号/有符号比较警告。是的,警告是有效的,但现实是有符号/无符号比较通常是有效的,我希望能够编写可读的代码,这些代码不会被“强制类型转换”混淆,从而消除警告。 这导致尝试通过模板元编程来增强代码,以根据需要进行转换/转换,而不是其他方式。我想出了这个函数来进行一般比较,然后基于它重写了我的三元函数:

template<typename Lhs, typename Rhs> auto cmp(Lhs const& lhs, Rhs const& rhs) -> std::strong_ordering { using Lhs_t = std::conditional_t<(std::is_signed<Lhs>() == std::is_signed<Rhs>()), // decltype(lhs), std::make_signed_t<Lhs>>; using Rhs_t = std::conditional_t<(std::is_signed<Lhs>() == std::is_signed<Rhs>()), // decltype(rhs), std::make_signed_t<Rhs>>; auto&& lhs_v = static_cast<Lhs_t>(lhs); auto&& rhs_v = static_cast<Rhs_t>(rhs); return lhs_v <=> rhs_v; }

编译得很漂亮,并通过了我的(整数)单元测试。然后我更新了所有函数以使用这个新范例,但比较时出现错误
std::string

。显然,在这种情况下这不起作用,所以我认为我需要 SFINAE 并开始与

std::enable_if
战斗。我正在输掉这场战斗。
我想做的是编写一个函数,如果所有参数都是整数,则将使用该函数(以消除有关有符号/无符号比较的编译器警告),并编写另一个用于所有其他类型的通用函数。

这就是我现在的位置:

template<typename Lhs, typename Rhs> typename std::enable_if_t<std::conjunction_v<std::is_integral_v<Lhs>, std::is_integral_v<Rhs>>, std::strong_ordering> cmp(Lhs const& lhs, Rhs const& rhs) { using Lhs_t = std::conditional_t<(std::is_signed<Lhs>() == std::is_signed<Rhs>()), // decltype(lhs), std::make_signed_t<Lhs>>; using Rhs_t = std::conditional_t<(std::is_signed<Lhs>() == std::is_signed<Rhs>()), // decltype(rhs), std::make_signed_t<Rhs>>; auto&& lhs_v = static_cast<Lhs_t>(lhs); auto&& rhs_v = static_cast<Rhs_t>(rhs); return lhs_v <=> rhs_v; } // Non-integral comparisons (e.g., strings) template<typename Lhs, typename Rhs> typename std::enable_if_t<std::negation_v<std::conjunction_v<std::is_integral_v<Lhs>, std::is_integral_v<Rhs>>>, std::strong_ordering> cmp(Lhs const& lhs, Rhs const& rhs) { return lhs <=> rhs; }

编译器报告如下:

/usr/src/project/util/unit/../bool.hh:20:5: note: template argument deduction/substitution failed: /usr/src/project/util/unit/../bool.hh: In substitution of 'template<class Lhs, class Rhs> std::enable_if_t<conjunction_v<is_integral_v<Lhs>, is_integral_v<Rhs> >, std::strong_ordering> {anonymous}::cmp(const Lhs&, const Rhs&) [with Lhs = unsigned int; Rhs = int]': /usr/src/project/util/unit/../bool.hh:53:28: required from 'bool is_le(const Lhs&, const Rhs&) [with Lhs = unsigned int; Rhs = int]' /usr/src/project/util/unit/bool_unittest.cpp:21:5: required from here /usr/src/project/util/unit/../bool.hh:19:36: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... _Bn> constexpr const bool std::conjunction_v<_Bn ...>' 19 | typename std::enable_if_t<std::conjunction_v<std::is_integral_v<Lhs>, std::is_integral_v<Rhs>>, std::strong_ordering> | ~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/src/project/util/unit/../bool.hh:19:36: note: expected a type, got 'std::is_integral_v<unsigned int>' /usr/src/project/util/unit/../bool.hh:19:36: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... _Bn> constexpr const bool std::conjunction_v<_Bn ...>' /usr/src/project/util/unit/../bool.hh:19:36: note: expected a type, got 'std::is_integral_v<int>'

很明显我做的元编程是错误的,但不清楚如何修复它。

c++ templates c++20
1个回答
0
投票

再次查看

cppreference页面

,我看到了这个:

模板参数

B...

- 实例化

Bi
的每个模板参数
Bi::value
必须可用作基类,并定义可转换为 bool
 的成员 
value

这帮助我理解
std::conjunction

实际上需要谓词类,而不是它们的值。

我将声明更改为:

template<typename Lhs, typename Rhs> typename std::enable_if_t<std::conjunction_v<std::is_integral<Lhs>, std::is_integral<Rhs>>, std::strong_ordering> cmp(Lhs const& lhs, Rhs const& rhs) { ... } template<typename Lhs, typename Rhs> typename std::enable_if_t<std::negation_v<std::conjunction<std::is_integral<Lhs>, std::is_integral<Rhs>>>, std::strong_ordering> cmp(Lhs const& lhs, Rhs const& rhs) { ... }

一切都已编译并且所有测试都通过了。

我留下这个问题,以防它可以帮助像我一样挣扎的其他人。

© www.soinside.com 2019 - 2024. All rights reserved.