简体   繁体   English

C++ 入门模板通用参考和参数推导

[英]C++ primer template universal reference and argument deduction

Hello I have this example from C++ primer:你好,我有这个来自 C++ 入门的例子:

 template <typename T> void f(T&& x) // binds to nonconstant rvalues { std::cout << "f(T&&)\\n"; } template <typename T> void f(T const& x) // lvalues and constant revalues { std::cout << "f(T const&)\\n"; }

And here is my attempt to test the output:这是我测试输出的尝试:

int main(){

    int i = 5;
    int const ci = 10;

    f(i); // f(T& &&) -> f(int&)
    f(ci); // f(T const&) -> f(int const&)
    f(5); // f(T &&) -> f(int&&)
    f(std::move(ci)); // f(T&&) -> f(int const&&)

    cout << '\n';
}

The output:输出:

f(T&&)
f(T const&)
f(T&&)
f(T&&)
  • In the book the version of f taking a forwarding reference is said to bind only to non-constant rvalues but in main I've passed a constant rvalue f(5) and f(std::move(ci)) but still the first version called.在这本书中,采用转发引用的f版本据说只绑定到非常量右值,但在main我已经传递了一个常数右值f(5)f(std::move(ci))但仍然是第一个版本称为。

  • Is there a way to call the second version f(T const&) passing an rvalue?有没有办法调用传递右值的第二个版本f(T const&) I know I can do it explicitly: f<int const&>(5);我知道我可以明确地做到这一点: f<int const&>(5); or f<int const&>( std::move(ci) );f<int const&>( std::move(ci) ); but I want to know where can be called passing in an rvalue?但我想知道在哪里可以调用传递右值? Thank you!谢谢!

  • I think the comment after the forwarding reference version of f is not correct: f(T&&) // binds to nonconstant rvalues because it can be bound to constant rvalues so for example:我认为f的转发参考版本之后的注释不正确: f(T&&) // binds to nonconstant rvalues因为它可以绑定到常量右值,例如:

     f(std::move(ci)); // f(int const&&) and not f(int const&)

The comments in the book are, evidently, not entirely correct.显然,书中的评论并不完全正确。 When you have the two overloads available of当你有两个可用的重载时

template <typename T> void f(T&& x);
template <typename T> void f(T const& x);

both of them can always be called with any argument (with some exceptions that I'll omit here), but the second one will be preferred if the argument is a const lvalue.它们总是可以用任何参数调用(有一些例外,我将在此处省略),但如果参数是const左值,则首选第二个。 The first one will be preferred under all other circumstances thanks to the reference collapsing rules that apply when deducing template arguments.由于在推导模板参数时适用的引用折叠规则,第一个在所有其他情况下将是首选。

However, let's say that T is fixed by an enclosing class:但是,假设T由封闭类固定:

template <class T>
struct S {
    void f(T&& x);
    void f(T const& x);
};

and let's assume that T is a non- const object type.让我们假设T是一个非const对象类型。 Now, the situation is different because T is not deduced when calling f .现在,情况有所不同,因为在调用f时不会推导出T The comments in the book seem to be referring to this latter situation, where the first S::f now may be called with non- const rvalues of type T but not with const rvalues of type T nor lvalues of (possibly const ) T .书中的评论似乎指的是后一种情况,其中第一个S::f现在可以用T类型的非const右值调用,但不能用T类型的const右值调用,也不能用(可能是constT左值调用。 The code, unfortunately, doesn't match up with the comments.不幸的是,代码与注释不匹配。

Let's go back to the actual code that's in the book.让我们回到书中的实际代码。 As I said, the function taking T const& will be preferred when the argument is a const lvalue.正如我所说,当参数是一个const左值时,采用T const&的函数将是首选。 Let's say that the argument is 5 , but you want to explicitly call the second function even though it would not normally be selected.假设参数是5 ,但您想显式调用第二个函数,即使它通常不会被选中。 There are a few ways to do this.有几种方法可以做到这一点。 The one that is easiest to read is to actually turn the argument into a const lvalue:最容易阅读的是将参数实际转换为const左值:

f((const int&)5);

Your suggestion of f<const int&>(5) also works, but is a bit more confusing.您对f<const int&>(5)也有效,但有点令人困惑。 The reason why it is confusing is that it requires the reader of the code to actually do the reference collapsing mentally and then remember that the first overload is less specialized than the second one.之所以令人困惑,是因为它要求代码的读者在心理上实际进行引用折叠,然后记住第一个重载不如第二个重载专门化。 A third method is:第三种方法是:

static_cast<void(*)(int const&)>(&f)(5);

Although this one is the hardest to read, the part before the (5) can be used whenever one particular overload needs to be extracted and bound to a function pointer.尽管这一部分最难阅读,但只要需要提取一个特定的重载并将其绑定到函数指针,就可以使用(5)之前的部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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