c++ - 复合赋值运算符的 C++ 概念
问题描述
我有一个普通二元运算符的概念
template<typename Op, typename T> concept is_binary_operation =
requires (const T& t1, const T& t2) // e.g. a+b
{
{Op()(t1,t2)}->std::convertible_to<T>;
};
以及复合赋值运算符的概念
template<typename Op, typename T> concept is_operation_and_assign =
requires (T& t1, const T& t2) // e.g a += b;
{
{Op()(t1,t2)}->std::convertible_to<T>;
};
对于复合赋值运算符,这按预期工作:
template<typename T> struct op_and_assign
{
T& operator()(T& t1, const T& t2)
{
t1 += t2;
return t1;
}
};
这个“is_operation_and_assign”而不是“is_binary_operation”
std::cout << is_binary_operation<op_and_assign<double>, double> << " ";
std::cout << is_operation_and_assign<op_and_assign<double>, double> << std::endl;
打印“0 1”。然而,std::plus 满足这两个概念:
std::cout << is_binary_operation<std::plus<double>, double> << " ";
std::cout << is_operation_and_assign<std::plus<double>, double> << std::endl;
打印“1 1”。
我该如何改变“is_operation_and_assign”的概念,以便得到输出“1 0”,即它可以由 op_and_assign 而不是 std::plus 来实现?
为了更清楚我需要什么:我有两个版本的算法,一个使用复合赋值运算符,一个使用二元运算符:
template<typename Op, typename T>
int f() requires is_operation_and_assign<Op, T>
{
return 0;
}
template<typename Op, typename T>
int f() requires is_binary_operation<Op, T>
{
return 1;
}
我可以调用 op_and_assign 的版本
f<op_and_assign<double>, double>();
但 std::plus 的版本
f<std::plus<double>, double>();
不编译。(错误:对“f”的调用不明确)
更新:同时我找到了一个解决方法:
当我简单地添加&& !is_binary_operation<Op, T>
到第一个时f
:
template<typename Op, typename T>
int f() requires (is_operation_and_assign<Op, T>
&& !is_binary_operation<Op, T>)
{
return 0;
}
template<typename Op, typename T>
int f() requires is_binary_operation<Op, T>
{
return 1;
}
那么第二个电话不再模棱两可,即两者
f<op_and_assign<double>, double>();
f<std::plus<double>, double>();
编译(并选择所需的功能)。
解决方案
澄清你的概念实际上在检查什么很重要,因为它不是你想象的那样。
这个:
template<typename Op, typename T> concept is_operation_and_assign =
requires (T& t1, const T& t2) // e.g a += b;
{
{Op()(t1,t2)}->std::convertible_to<T>;
};
检查您是否可以Op()(t1, t2)
使用 aT&
和 a调用,T const&
并且您得到满足convertible_to<T>
. 当您提供:
template<typename T> struct op_and_assign
{
T& operator()(T& t1, const T& t2)
{
t1 += t2;
return t1;
}
};
作为第一个模板参数,它实际上检查了什么?这是一个未计算的表达式,我们正在检查是否可以调用op_and_assign<T>()
. 我们没有评估呼叫操作员的主体,我们只是检查它是否是一个有效的呼叫。所以这与我们写的没有什么不同:
template<typename T> struct op_and_assign
{
T& operator()(T& t1, const T& t2);
};
它没有被评估,没有实体,所以唯一重要的是约束。在这里,没有约束,所以op_and_assign
只要参数是可转换的,它总是可以调用的。
当你这样做时:
is_binary_operation<op_and_assign<double>, double>
您实际上是在询问是否可以适当地转换参数。对于is_binary_operation
,您提供了两个类型的参数double const&
(来自您的 requires 表达式)但op_and_assign<double>
需要一个double&
. 这就是为什么此特定检查不起作用的原因。
对于如何修复它。op_and_assign
这应该看起来像这样:
struct op_and_assign
{
template <typename T, typename U>
auto operator()(T&& t, U&& u) const -> decltype(t += u);
};
现在我们实际上正在检查我们是否可以执行+=
.
但这不会改变您无法分配给double const&
. 即使您没有进行您打算进行的检查,您也会在那里得到正确的答案。
推荐阅读
- json - 使用 gson 加载 JSON
- reactjs - 对于基于类的组件,useRouteMatch 的等价物是什么?
- javascript - 如何从字符串化数组中删除引号
- c++ - 错误:从基类父亲派生类儿子时未定义基类
- python-3.x - 如何使用 python 在 xlsxwriter 中添加标注
- visual-studio-code - 使 Visual Studio Code 始终显示错误,即使在关闭有错误的文件后也是如此?
- tcl - 使用 tcl glob 进行通配符搜索
- javascript - 按子值寻址 Firebase 对象,然后修改该对象?
- algorithm - 如果我切割不同长度的杆,我如何获得 2^(n-1) 的结果总数?其中 n 是杆的长度
- laravel - Laravel Voyager,如何使用 eloquent 模型翻译表格