【问题标题】:Issue with std::reference_wrapperstd::reference_wrapper 的问题
【发布时间】:2015-07-27 14:02:24
【问题描述】:

使用以下代码可以明确问题:

#include <functional>
#include <iostream>
#include <vector>

int main() {
  //std::vector<int> a, b;
  int a = 0, b = 0;
  auto refa = std::ref(a);
  auto refb = std::ref(b);
  std::cout << (refa < refb) << '\n';
  return 0;
}

如果我使用带注释的std::vector&lt;int&gt; a, b; 而不是int a = 0, b = 0;,则代码无法在任何 GCC 5.1、clang 3.6 或 MSVC'13 上编译。在我看来,std::reference_wrapper&lt;std::vector&lt;int&gt;&gt; 可以隐式转换为 std::vector&lt;int&gt;&amp;,即 LessThanComparable,因此它本身应该是 LessThanComparable。有人可以向我解释一下吗?

【问题讨论】:

  • @Barry: It's actually not :P 尽管有运营商。
  • 错误信息是什么,OP?
  • @imreal 该类型未定义&lt; 运算符。它是一个非成员函数
  • @imreal:我不知道。这让我很惊讶。
  • @imreal:嗯,嗯,有一个概念列表,它们的要求意味着 LessThanComparable 不是其中之一?

标签: c++ c++11 language-lawyer implicit-conversion reference-wrapper


【解决方案1】:

问题是std::vector 的非成员operator&lt; 是一个函数模板:

template< class T, class Alloc >
bool operator<( const vector<T,Alloc>& lhs,
                const vector<T,Alloc>& rhs );

这里做模板类型推导时考虑隐式转换,[temp.arg.explicit]强调if:

隐式转换(第 4 条)将对函数参数执行以将其转换为 对应的函数参数if参数类型不包含参与的template-parameters 在模板参数推导中。

但是在这种情况下,参数类型确实参与了推导。这就是它找不到的原因。如果我们编写自己的-模板operator&lt;:

bool operator<(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
    return true;
}

您的代码将按预期工作。但是,要使用通用的,您必须明确地提取参考:

std::cout << (refa.get() < refb.get()) << '\n';

【讨论】:

  • 非常有趣。您引用的规范部分的基本原理是什么?
  • 如果operator&lt; 写成friend bool Koenig 运算符,它会通过转换找到吗?我想知道这是“向量很旧,他们不知道正确的方法”还是“伪引用很难,引用包装器应该添加 SFINAE 检测重载”(可能两者兼而有之)的问题。
  • @Yakk 作为非模板(例如friend bool operator&lt;(const vector&amp; lhs, const vector&amp; rhs) { ... }),是的,它会被找到。
  • @Barry friend bool operator&lt;(const vector&amp; lhs, const vector&amp; rhs) { ... } 不应该还是一个模板吗?
【解决方案2】:

你确定吗

std::vector<int> a, b;

正在做它应该做的事吗?以这个为例

#include <functional>
#include <iostream>
#include <vector>

int main() {
  std::vector<int> a, b;
  //int a = 0, b = 0;
  a.push_back(42);
  a.push_back(6);
  a.push_back(15);
  for (int ii=0; ii<43; ii++) {
    b.push_back(ii);
  }
  auto refa = std::ref(a);
  auto refb = std::ref(b);
  std::cout<<&refa<<std::endl;
  std::cout<<&refb<<std::endl;
  std::cout<<"Contents of vector A"<<std::endl;
  for(auto n : a)
  {
    std::cout<<' '<<n;
  }
  std::cout<<std::endl<<"Contents of vector b: ";
  for (auto n : b){
    std::cout<<' '<<n;
  }
  //std::cout << (refa < refb) << '\n';
  return 0;
}

结果

0x7fff5fbff0c0
0x7fff5fbff0b8
Contents of vector A
 42 6 15
Contents of vector b:  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

最终

std::vector<int> a, b;

创建两个独立的整数向量 a 和 b,它们都没有内容;这不是声明具有成员 a 和 b 的单个向量的方式。

int a=0, b=0;

声明两个独立的整数 a 和 b,它们的值都为 0。这两个代码 sn-ps 声明了完全不同的变量,不应互换使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    • 2020-12-23
    相关资源
    最近更新 更多