【问题标题】:C++ : struggle with generic const pointerC++:与通用 const 指针斗争
【发布时间】:2009-10-30 00:18:07
【问题描述】:

我在一些模板代码中遇到了一些令人讨厌的 const 正确性问题,最终归结为以下观察:由于某种原因,给定一个 STL-ish 容器类型 T,const typename T::pointer 实际上似乎并不产生一个常量指针类型,即使T::pointer 等价于T::value_type*

下面的例子说明了这个问题。假设您有一个模板化函数,该函数接受一个必须满足 STL 随机访问容器概念要求的容器。

template <class Container>
void example(Container& c)
{
    const typename Container::pointer p1 = &c[0]; // Error if c is const
    const typename Container::value_type* p2 = &c[0]; 
}

那么,如果我们给这个函数传递一个 const 容器...

const std::vector<int> vec(10);
example(vec);

...我们从const int*int* 的转换无效。但是为什么在这个例子中const typename Container::pointerconst int* 不一样呢?

请注意,如果我将 const typename Container::pointer 更改为简单的 typename Container::const_pointer 它编译得很好,但是,据我所知, const_pointer typedef 是一个扩展,(我没有看到它在 C++ 标准容器要求中提到(23.5,表 65)),因此我不想使用它。

那么我怎样才能从容器 T 中获得一个通用的、常量正确的指针类型呢? (如果不使用 boost::mpl::if_ 和 type_traits 来检查容器是否为常量,我真的看不到如何做到这一点......但必须有一种不那么冗长的方法来做到这一点)

编辑:以防万一,我使用 gcc 4.3.2 来编译它。

【问题讨论】:

    标签: c++ templates stl constants


    【解决方案1】:

    它不起作用,因为您的const 不适用于您认为它适用的内容。例如,如果您有

    typedef int* IntPtr;
    

    然后

    const IntPtr p;
    

    不代表

    const int* p;
    

    而是代表

    int* const p;
    

    Typedef-name 不是宏。一旦将类型的“指针性”包装到 typedef-name 中,就无法再使用它来创建指向 const 的指针类型了。 IE。绝对没有办法使用上面的IntPtr typedef-name 来产生等效的

    const int* p;
    

    您必须明确地使用指针类型(就像您使用 value_type 所做的那样),或者检查您的容器是否定义了不同的 typedef-name,const 已经被“包裹”在“内部”(例如 const_pointer 或其他东西像那样)。

    【讨论】:

    • 这可能很难记住。我遇到的最好的提示是将 R 读取到 L。“int* const p”是“指向 int 的 const 指针”,即指针是 const 但 int 是可变的。 “const int *p”是“指向为 const 的 int 的指针”,即指针是可变的,但 int 是 const。
    • 这个答案(和其他)不正确。所需要的只是使用模板来删除指针。详情见我的回答。
    • @darune:首先,这个答案没有“不正确”的地方。其次,这个答案是在 2009 年写的,当时根本没有 std::remove_pointer 这样的东西。第三,不,当/如果您可以直接访问指针类型时,您不需要使用std::remove_pointer
    • @AnT 我看到的不正确部分是“绝对没有办法使用上面的 IntPtr typedef-name 来产生等效的”。 std::remove_ptr 使用 2009 c++ 很容易实现,并且已经在 boost 中使用了很长时间。顺便提一句。这不是责备游戏,而是为其他用户服务。
    【解决方案2】:

    这个:

    typename Container::pointer
    

    类型为int*(在我们的例子中)。我不知道术语,很抱歉,但指针指向一个类型。也就是说,Container::pointer 是一个指向可变 T 的指针,添加 const 只会使它成为一个 const 指针(而不是指向 const 的指针),因为 Container::pointer 已经被定义为指向一个可变 T。

    似乎只有const_pointer,要么来自班级,要么来自你自己:

    typedef const typename Container::value_type* const_pointer
    

    会起作用的。

    【讨论】:

      【解决方案3】:

      分配器要求(参见 20.1.5,表 32,“分配器要求”)规定 STL 容器的分配器应具有Allocator::const_pointer。所有 STL 容器(第 23 节中列出的八个容器)都将Container::const_pointer typedef 定义为:

      typedef typename Allocator::const_pointer const_pointer;
      

      但是,正如您在问题中所述,容器(除了这八个之外)不需要具有 Container::const_pointer 类型定义。

      【讨论】:

      • 你能澄清一下吗?我明白您所说的将 const_pointer 作为分配器要求的一部分(在 20.1.5 中),但它在哪里说 Containers 必须定义一个 const_pointer typedef?我看到的最接近的是 20.1.5.4,它说容器实现可以假设分配器有一个 const_pointer typedef,不一定容器本身应该定义一个 public const_pointer typedef。
      • 我并不是要暗示 STL 要求容器定义 const_pointer typedef,只是所有 STL 容器都定义了 const_pointer typedef。对困惑感到抱歉;我更新了我的答案,试图让它更清楚一点。
      【解决方案4】:

      这可能与此处相关(来自SGI STL reference):

      [6] 与引用 [5] 的情况一样,指针类型必须具有与 C++ 指针相同的语义,但实际上不必是 C++ 指针。然而,与“智能引用”不同,“智能指针”是可能的。这是因为用户定义类型可以定义解引用运算符和指针成员访问运算符、operator* 和 operator->。

      【讨论】:

      • 然而,在这种情况下,T::pointerT::value_type* 相同(即T::pointer 是一个实际的原始指针),因此满足了要求。 ——查尔斯·萨尔维亚
      【解决方案5】:

      可以通过使用模板来实现。诀窍是先删除指针,然后在类型上应用 const,最后将指针应用到类型 - 例如使用 std::remove_pointer 产生:

      typedef const std::remove_pointer<Container::pointer>::type* PointerToConst;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-18
        • 2018-05-23
        • 2013-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多