简体   繁体   English

复合赋值运算符的 C++ 概念

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM