jar*_*son 7 c++ effective-c++ c++-concepts forwarding-reference c++20
Scott Meyers 所著的《Effective Modern C++》一书中给出了“避免通用引用重载”的建议(第 26/27 项)。他的理由是,在几乎所有对包含通用引用的重载函数的调用中,编译器都会解析为通用引用,即使这通常不是您想要解析的函数。(所以我认为这段代码很糟糕?)
template <typename T>
void foo(T&& t) {
// some sort of perfect forwarding
}
void foo(string&& t) {
// some sort of move operation
}
Run Code Online (Sandbox Code Playgroud)
上面的例子是精心设计的,可能会被替换为 2 个函数。
我认为更难解决且不那么做作的另一个例子是他在第 26 项中实际给出的例子。
class Foo {
// a decent amount of private data that would take a while to copy
public:
// perfect forwarding constructor, usually the compiler resolves to this...
template <typename T>
explicit Foo(T&& t) : /* forward the information for construction */ {}
// constructor with some sort of rValue
explicit Foo(int);
// both the below are created by the compiler he says
// move constructor
Foo(Foo&& foo);
// copy constructor (used whenever the value passed in is const)
Foo(const Foo& foo);
}
// somewhere else in the code
Foo f{5};
auto f_clone(f);
Run Code Online (Sandbox Code Playgroud)
Scott 解释说,不是调用移动构造函数或复制构造函数,而是调用转发构造函数,auto f_clone(f)因为编译器规则首先解析为转发构造函数。
在书中,他解释了此方法的替代方案以及通用引用重载的其他一些示例。其中大多数对于 C++11/14/17 来说似乎都是很好的解决方案,但我认为有更简单的方法可以使用 C++20 概念来解决这些问题。除了对转发构造函数的某种约束之外,代码与上面的代码相同:
template <typename T>
requires = !(typename Foo) // not sure what would need to be put here, this is just a guess
explicit Foo(T&& t) : /* forward the information for construction */ {}
Run Code Online (Sandbox Code Playgroud)
我不知道这是否是正确的语法,我对 C++ 概念非常陌生
对我来说,应用于转发函数的 C++ 概念似乎是一个可以应用于每种情况的通用解决方案,但我不确定
我的问题有多个部分:
我会说不。我的意思是,概念有帮助,因为语法比我们以前的更好,但它仍然是同样的问题。
这是一个现实生活中的示例:std::any可以从任何可复制构造的类型构造。所以你可以从以下开始:
struct any {
template <class T>
requires std::copy_constructible<std::decay_t<T>>
any(T&&);
any(any const&);
};
Run Code Online (Sandbox Code Playgroud)
问题是,当你做这样的事情时:
any a = 42; // calls any(T&&), with T=int
any b = a; // calls any(T&&), with T=any
Run Code Online (Sandbox Code Playgroud)
因为any它本身当然是可复制构造的。这使得构造函数模板变得可行,并且具有更好的匹配性,因为它是一个较少 const 限定的引用。
因此,为了避免这种情况(因为我们想要b持有 an int,而不是持有any持有 an 的 an int),我们必须将自己排除在考虑范围之外:
struct any {
template <class T>
requires std::copy_constructible<std::decay_t<T>>
&& (!std::same_as<std::decay_t<T>, any>)
any(T&&);
any(any const&);
};
Run Code Online (Sandbox Code Playgroud)
这与我们在 C++17 中以及更早版本 Scott Meyers 撰写他的书时必须做的事情相同。至少,解决问题的机制是相同的——即使语法更好。