如何在C++中实现通用指针类型

Joh*_* Li 4 c++ pointers boost-any heterogeneous-array

在C中,可以将数据指针分配给void指针,然后将其转换回原始类型,该数据指针将被恢复.语言标准保证这种转换不会丢失信息.这通常意味着(不一定,但对大多数平台来说都是如此),void指针的大小与数据指针的大小相同.因此,可以指望这些事实使用void指针作为异构类型的一般指针,而void指针本身具有统一的大小和表示.例如,一个有一个void指针数组,其元素指向动态分配的不同类型的对象.构造这样的数组使某些事情变得方便.我的问题是:如何实现类似的东西,C++中的通用指针类型,它符合以下内容:(假设g_pointer是类名)

我刚刚发现了boost :: any,看看它的介绍看起来似乎可能是我想要的,尽管可能不是这样.所以任何熟悉boost :: any的人都欢迎发表评论.

更新:(回复一些评论)

  • g_pointer类型对象应该知道它指向的对象的基础类型.因此,recover方法应始终返回该类型的指针.
  • 一般指针类型,意味着对任何对象的引用,恕我直言,对任何支持面向对象范式的语言都是合理的.

更新:谢谢@Caleth,std :: any很棒.

xsk*_*xzr 5

在C++中是不可能的.因为表达式的类型g_ptr.recover()是在编译时确定的,所以它不能存储在运行时确定的基础类型的信息.


如果你可以容忍像这样的表达式g_ptr.recover<T>(),你可以g_pointer通过包装a void*和a 来实现,const std::type_info&它存储指针指向的实际类型的信息,例如

class g_pointer {
public:
    template <class T>
    constexpr g_pointer(T *data) noexcept : _data(data), _object_type(typeid(T)) {}

    template <class T>
    T* recover() const {
         if (typeid(T) == _object_type) return static_cast<T*>(_data);
         else throw std::bad_cast{};
    }
private:
    void *_data;
    const std::type_info &_object_type;
};
Run Code Online (Sandbox Code Playgroud)

请注意,此g_pointer行为类似于原始指针而非智能指针,这意味着它不拥有它指向的对象.


上面的实现中仍然存在一个缺陷:const T*无法隐式转换为void*,因此一般指针不能成立const T*.要处理const限定符,您可以在恢复时更改_datato 的类型const void*并使用它const_cast.另外,recover应该拒绝从g_pointer持有指向const对象的指针返回指向非const对象的指针.但是,typeid运算符忽略顶级const限定符,因此我们需要一个额外的数据成员来记录指针是否指向最初的const对象.

class g_pointer {
public:
    template <class T>
    constexpr g_pointer(T *data) noexcept : _data(data), 
                                            _object_type(typeid(T)),
                                            _is_const(std::is_const_v<T>) 
                                         // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ change here
    {
    }

    template <class T>
    T* recover() const {
         if (
             typeid(T) != _object_type ||
             (_is_const && !std::is_const_v<T>) // try to obtain T* while const T* is held
         ) {
             throw std::bad_cast{};
         }
         else return static_cast<T*>(const_cast<void*>(_data));
                                  // ^^^^^^^^^^^^^^^^^ change here
    }
private:
    const void *_data;
 // ^^^^^ change here
    const std::type_info &_object_type;
    bool _is_const; // <-- record whether the pointer points to const T
};
Run Code Online (Sandbox Code Playgroud)