C++ 模板中的 auto&& 与 constrained auto&&

Bri*_*939 4 c++ forwarding-reference c++20

MSVC /std:c++20 报告约束自动&& 的错误如下所示

#include<concepts>

class Base { public: Base() {} };
class Derived : public Base { public: Derived() {} };

template<typename T> concept con = std::is_class_v<T>
&& std::derived_from<T, Base>;
void f(con auto&& x) {}

int main()
{
   f(Derived()); // r value: Ok

   Derived d;
   f(d); // l-value: no matching overloaded function found
}
Run Code Online (Sandbox Code Playgroud)

从“con auto&&”中删除“con”,上面的代码编译没有错误。我想了解为什么向 auto&& 模板参数添加约束会将其从“通用引用”更改为仅 R 值引用。此行为符合 C++20 标准还是 MSVC 独有的行为?

在互联网上搜索 C++ 论坛,没有找到任何解释这种特定语言用例的内容。然而,可能有一些我错过或没有注意到的事情。

Nik*_*iou 6

因为在实例化时Derived&你会检查

std::derived_from<Derived&, Base>
//              this guy ^          
Run Code Online (Sandbox Code Playgroud)

为了使您的概念不受不同价值类别的影响,您可以使用std::decay_t

template<typename T> 
concept con = 
    std::is_class_v<std::decay_t<T>> && 
    std::derived_from<std::decay_t<T>, Base>;
Run Code Online (Sandbox Code Playgroud)

因此纯粹是在不检查其值类别的情况下检查类型

演示


Bar*_*rry 5

我想了解为什么向auto&&模板参数添加约束会将其从“通用引用”更改为仅 R 值引用。

它没。这里的函数参数仍然是转发引用。

但是,您的约束要求推导的类型是 (a) 派生自 的类类型 (b) Base。在调用中f(d),模板参数推导为Derived&,它不是类类型(也不是派生自Base),因此您已经有效地使函数模板仅接受右值。

您正在寻找的是

template <class T>
    requires std::derived_from<std::remove_cvref_t<T>, Base>
void f(T&& x);
Run Code Online (Sandbox Code Playgroud)

或者将其放入remove_cvref_t概念定义中。

请注意,该is_class检查是多余的。只有类类型可以派生自另一种类型。