[英]C++ concept for compound assignment operators
I have a concept for normal binary operators我有一个普通二元运算符的概念
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>;
};
and a concept for compound assignment operators以及复合赋值运算符的概念
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>;
};
For compound assignment operators this works as expected:对于复合赋值运算符,这按预期工作:
template<typename T> struct op_and_assign
{
T& operator()(T& t1, const T& t2)
{
t1 += t2;
return t1;
}
};
This "is_operation_and_assign" but not "is_binary_operation"这个“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;
prints "0 1".打印“0 1”。 std::plus, however, satisfies both concepts:
然而,std::plus 满足这两个概念:
std::cout << is_binary_operation<std::plus<double>, double> << " ";
std::cout << is_operation_and_assign<std::plus<double>, double> << std::endl;
prints "1 1".打印“1 1”。
How do I have to change the concept "is_operation_and_assign" so that I get the output "1 0", ie so that it will fulfilled by op_and_assign but not by std::plus?我如何必须更改“is_operation_and_assign”的概念,以便获得 output“1 0”,即它可以由 op_and_assign 而不是 std::plus 实现?
To make more clear what I need: I have two versions of an algorithm, one using the compound assignment operator, one using the binary operator:为了更清楚我需要什么:我有两个版本的算法,一个使用复合赋值运算符,一个使用二元运算符:
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;
}
I can call the version for op_and_assign我可以调用 op_and_assign 的版本
f<op_and_assign<double>, double>();
but the version for std::plus但 std::plus 的版本
f<std::plus<double>, double>();
does not compile.不编译。 (error: call to 'f' is ambiguous)
(错误:对“f”的调用不明确)
Update : in the meanwhile I found a workaround:更新:同时我找到了一个解决方法:
When I simply add &&,is_binary_operation<Op, T>
to the first 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;
}
then the second call is no longer ambiguous, ie both那么第二个电话不再模棱两可,即两者
f<op_and_assign<double>, double>();
f<std::plus<double>, double>();
compile (and choose the desired function).编译(并选择所需的功能)。
It's important to clarify what actually your concept is checking, because it's not what you think it is.澄清你的概念实际上在检查什么很重要,因为它不是你想象的那样。
This:这个:
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>;
};
Checks that you can invoke Op()(t1, t2)
with a T&
and a T const&
and that you get something that satisfies convertible_to<T>
.检查您是否可以使用
T&
和T const&
调用Op()(t1, t2)
并且您得到满足convertible_to<T>
的内容。 When you provide:当您提供:
template<typename T> struct op_and_assign
{
T& operator()(T& t1, const T& t2)
{
t1 += t2;
return t1;
}
};
as the first template parameter, what does that actually check?作为第一个模板参数,它实际上检查了什么? This is an unevaluated expression, we're checking to see if we can invoke
op_and_assign<T>()
.这是一个未计算的表达式,我们正在检查是否可以调用
op_and_assign<T>()
。 We're not evaluating the body of the call operator, we're just checking to see if it's a valid call.我们没有评估呼叫操作员的主体,我们只是检查它是否是一个有效的呼叫。 So it's no different than if we wrote:
所以这与我们写的没有什么不同:
template<typename T> struct op_and_assign
{
T& operator()(T& t1, const T& t2);
};
It's unevaluated, there's no body, so the only things that matter are constraints.它没有被评估,没有实体,所以唯一重要的是约束。 Here, there are no constraints, so
op_and_assign
is always invokable as long as the arguments are convertible.这里没有约束,所以只要
op_and_assign
是可转换的, op_and_assign 总是可以调用的。
When you do this:当你这样做时:
is_binary_operation<op_and_assign<double>, double>
You're effectively asking if you can convert the arguments appropriately.您实际上是在询问是否可以适当地转换 arguments。 For
is_binary_operation
, you're providing two arguments of type double const&
(from your requires expression) but op_and_assign<double>
needs to take one double&
.对于
is_binary_operation
,您提供两个 arguments 类型为double const&
(来自您的 requires 表达式),但op_and_assign<double>
需要一个double&
。 That's why this particular check doesn't work.这就是为什么此特定检查不起作用的原因。
For how to fix it.对于如何修复它。
op_and_assign
which should probably look something like this: op_and_assign
应该看起来像这样:
struct op_and_assign
{
template <typename T, typename U>
auto operator()(T&& t, U&& u) const -> decltype(t += u);
};
Now we're actually checking if we can perform +=
.现在我们实际上正在检查我们是否可以执行
+=
。
But that won't change that you can't assign to a double const&
.但这不会改变您不能分配给
double const&
的情况。 You're getting the correct answer there, even if you weren't doing the check you intended to.即使您没有进行您打算进行的检查,您也会在那里得到正确的答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.