具有代理迭代器/引用和auto的容器

时间:2013-11-21 15:10:27

标签: c++ c++11 iterator generic-programming c++14

我正在实现一个带有代理迭代器/引用类型类似的容器到std::vector<bool>并碰撞到以下问题,我将继续以std::vector<bool>为例(这个问题与std::vector<bool>无关!):

#include <vector>
#include <type_traits>
int main() {
  using namespace std;
  vector<bool> vec = {true, false, true, false};
  auto value = vec[2];  // expect: "vector<bool>::value_type"
  const auto& reference = vec[2]; // expect: "vector<bool>::const_reference"

  static_assert(is_same<decltype(value), vector<bool>::value_type>::value, 
                "fails: type is vector<bool>::reference!");
  static_assert(is_same<decltype(reference), 
                        vector<bool>::const_reference>::value,
                "fails: type is const vector<bool>::reference&!"); 

  /// Consequence:
  auto other_value = value; 
  other_value = false; 
  assert(vec[2] == true && "fails: assignment modified the vector");
  • 有没有办法实现代理类型,以便静态断言都通过?

  • 在实施此类容器时是否有关于如何处理此问题的指导原则?

也许使用转化运算符auto / auto& / auto&& / const auto...

编辑:重新设计示例以使其更清晰。感谢@LucDanton在下面的评论。

2 个答案:

答案 0 :(得分:3)

众所周知,vector<bool>与主要模板vector<T>相比具有非通用接口

相关的区别在于,嵌套类型referenceconst_reference在{1}} typedef T&T const&一般情况下都是reference {> 1}的强>代理类 bool值类型 vector<bool>

访问向量元素时,同样重要的是要记住向量对象的常量确定{{1}是否返回referenceconst_reference }。此外,operator[]将删除参考限定符,而auto将保留参考限定符。

让我们看一下decltype / bool的非const / const向量,并使用intautodecltype(auto)(普通auto const&将导致代理的实时问题)。您会收到以下行为:

auto&

Live Example

请注意,对于非const #include <vector> #include <type_traits> #include <typeinfo> #include <iostream> #include <ios> int main() { using namespace std; vector<bool> vb = { true, false, true, false }; vector<int > vi = { 1, 0, 1, 0 }; auto vb2 = vb[2]; // vector<bool>::reference != bool auto vi2 = vi[2]; // int decltype(auto) rvb2 = vb[2]; // vector<bool>::reference decltype(auto) rvi2 = vi[2]; // int& auto const& crvb2 = vb[2]; // vector<bool>::reference const& != bool const& auto const& crvi2 = vi[2]; // int const& auto ovb2 = vb2; ovb2 = false; // OOPS ovb2 has reference semantics cout << boolalpha << (vb[2] == true) << "\n"; auto ovi2 = vi2; ovi2 = 0; // OK, ovi2 has value semantics cout << boolalpha << (vi[2] == 1) << "\n"; static_assert(is_convertible<decltype(vb2), vector<bool>::value_type>::value, ""); static_assert(is_same <decltype(vi2), vector<int >::value_type>::value, ""); static_assert(is_same <decltype(rvb2), vector<bool>::reference>::value, ""); static_assert(is_same <decltype(rvi2), vector<int >::reference>::value, ""); static_assert(is_convertible<decltype(crvb2), vector<bool>::const_reference>::value, ""); static_assert(is_same <decltype(crvi2), vector<int >::const_reference>::value, ""); vector<bool> const cvb = { true, false, true, false }; vector<int > const cvi = { 1, 0, 1, 0 }; auto cvb2 = cvb[2]; // vector<bool>::const_reference == bool auto cvi2 = cvi[2]; // int decltype(auto) rcvb2 = cvb[2]; // vector<bool>::const_reference == bool decltype(auto) rcvi2 = cvi[2]; // int const& auto const& crcvb2 = cvb[2]; // vector<bool>::reference const& != bool const& auto const& crcvi2 = cvi[2]; // int const& static_assert(is_same <decltype(cvb2), vector<bool>::value_type>::value, ""); static_assert(is_same <decltype(cvi2), vector<int >::value_type>::value, ""); static_assert(is_same <decltype(rcvb2), vector<bool>::const_reference>::value, ""); static_assert(is_same <decltype(rcvi2), vector<int >::const_reference>::value, ""); static_assert(is_convertible<decltype(crcvb2), vector<bool>::const_reference>::value, ""); static_assert(is_same <decltype(crcvi2), vector<int >::const_reference>::value, ""); auto ocvb2 = cvb2; ocvb2 = false; // OK, ocvb2 has value semantics cout << boolalpha << (cvb[2] == true) << "\n"; auto ocvi2 = cvi2; ocvi2 = 0; // OK, ocvi2 has value semantics cout << boolalpha << (cvi[2] == 1) << "\n"; } ,在vector<bool>上使用auto将为您提供一个没有值语义的引用代理。使用operator[]可以避免这种情况。我不知道如何以其他任何方式解决这个问题。

const vector<bool>在行为上是等效的,但在auto const&内有is_convertible而不是is_same。我认为这是最好的。

请注意,对于代理容器上的一般迭代和STL算法,事情并不是那么黯淡。请参阅Hinnant's column on this

答案 1 :(得分:3)

代理与auto互动性不佳,正是因为auto揭示了应该隐藏的类型。

operator auto风格的事情有一半的要求(基本上,“当我将其作为一种类型推断时,请使用此类型”),但AFAIK甚至没有将其作为正式提案。

另一个问题是vector<bool>是意外的,因为它是使用代理的{em>仅实例化vector。还有其他初步提案要求弃用vector<bool>并最终恢复为非特殊,并引入了一个特殊目的bitvector类来取代它。