【问题标题】:Template universal reference in c++ does not compilec++ 中的模板通用引用无法编译
【发布时间】:2018-05-24 22:53:47
【问题描述】:

我无法理解为什么我的代码无法在此处编译。我从标准库中收到了很多错误消息,类似于

main3.cpp:10:20:   required from ‘void addAndCout(T&&) [with T = const char (&)[11]]’
main3.cpp:20:28:   required from here
/usr/include/c++/5/bits/alloc_traits.h:450:27: error: forming pointer to reference type ‘const char (&)[11]’
       using pointer = _Tp*;
                           ^
/usr/include/c++/5/bits/alloc_traits.h:453:39: error: forming pointer to reference type ‘const char (&)[11]’
       using const_pointer = const _Tp*;

这对我来说没有意义,因为我认为 T&& 在没有推导 T 时是一个通用引用,它应该能够绑定到右值或左值。发布的这个示例是我试图从 Scott Meyer 的“Effective Modern C++”中复制一个部分,其中我正在阅读有关通用引用的内容。 Photo of example from the book

我只是想知道为什么这不会编译或者我在这里缺少什么,因为据我所知它实际上与示例相同。

#include <iostream>
#include <vector>
#include <string>
using std::cout;
using std::endl;

template<typename T>
void addAndCout(T &&name)
{
    std::vector<T> v;

    cout << name << endl;
    v.emplace_back(std::forward<T>(name));
}

int main(int argc, char **argv)
{
    std::string name {"test"};

    addAndCout(std::string("rvalue")); // FINE      move rvalue instead of copying it
    addAndCout("New string");          // ERROR     make a new string instead of copying
    addAndCout(name);                  // ERROR     copy lvalue
}

【问题讨论】:

  • 您能解释一下局部向量的用途吗?当函数返回时它会被销毁,因此无论如何在其中存储值都是多余的。

标签: c++ c++14 forwarding-reference


【解决方案1】:

不能有vector 的引用,也不能有C 样式数组的向量。当参数是左值和/或 C 样式数组时,std::vector&lt;T&gt; v; 行编译失败。

您的代码与书中的不同之处在于您使用std::vector&lt;T&gt; v; 而本书没有。

为了支持addAndCout(name); 的用法,您可以将向量定义更改为:

std::vector< typename std::remove_cv<typename std::remove_reference<T>::type>::type > v;

remove_cv 是因为也不能有 const 对象的向量)。

要支持 C 风格的数组,最简单的方法是添加一个额外的重载:

template<typename T, size_t N>
void addAndCout(T (&name)[N])
{
     // do whatever...
}

【讨论】:

  • vector 的模板参数也不能是const、数组或函数。所以std::decay 可能会比std::remove_reference 更好。
  • @aschepler 我添加了remove_cv。我认为decay 在数组上的行为可能不适合这个用例,目的是存储参数的副本/移动。虽然我不太清楚意图是什么,因为将项目存储在本地向量中是多余的
【解决方案2】:
  • 当你做addAndCout(std::string("rvalue")); 这是右值 引用和模板参数 T 是 std::string 和 this::std::vector&lt;std::string&gt; v; 有效。
  • 但是当你这样做时,addAndCout("New string"); T 被推断为对 const char 数组的引用,并且你不能有引用向量
  • 当您执行addAndCout(name); 时,您正在传递左值引用,并且 T 变为 std::string&amp; 和类似的你不能有引用向量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多