C ++:确定类指针类型的,在使用升压多指标的 [英] C++: Determine the class of a pointer type in the use of Boost MultiIndex

查看:197
本文介绍了C ++:确定类指针类型的,在使用升压多指标的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在回答这个问题具有普遍的应用程序,但我会与下面的例子激励吧:

我有以下的模板类:

 模板< typename的V>
集合类
{
上市:
    结构ID {}​​;
    结构名{};
    //由V型参数集合,由一个字符串'名称'索引
    //一个整数,ID
    //该V型必须实现'get_id()'和'GET_NAME()'功能
    的typedef multi_index_container的<
        五,
        的indexed_by<
            ordered_unique<
                标签< ID>中const_mem_fun< V,无符号整型,&安培; V :: get_id> >中
            ordered_unique<
                标签<名称>,&const_mem_fun LT; V,标准::字符串,&安培; V :: GET_NAME> >
        >
    > ni_collection;
>

我要修改这个模板,这样我可以创建一个对象,其指针或它们的引用集合:收藏<的OBJ> 收集和LT;的std ::的unique_ptr<&的OBJ GT;> 收集和LT;的OBJ *>

我将如何修改我的模板来实现这一目标?

--- ---更新
我曾在这里发布一个相关的问题:
计算类型的函数指针的

合成两地优秀的答案,我终于实现了我最初的目标。这里是我目前执行的细节:

 模板< typename的V>
集合类
{
私人的:
//返回未修饰对象的类型A型级功能
//所以unrwap_object_type<小部件* GT; =小工具
// unwrap_object_type<的std ::的unique_ptr<窗​​口小部件>> =小工具
// unwrap_object_type<窗​​口小部件> =小工具
模板< typename的T,类型名称=无效>
结构unwrap_object_type {typedef的T形; };模板< typename的T>
结构unwrap_object_type< T *,无效> {typedef的T形; };模板< typename的T>
结构unwrap_object_type< T,
    类型名称的std ::有条件<假的,
        typename的T :: ELEMENT_TYPE,无效> ::类型>
{
  的typedef typename的T :: ELEMENT_TYPE类型;
};
//////这样QHNETO_COLLECTION<小部件>中QHNETO_COLLECTION< Widet *>中
//和QHNETO_COLLECTION<的std ::的unique_ptr<窗​​口小部件>>是有效的
的typedef typename的unwrap_object_type< V> :: W型;//标签为集合的两个指标(id和name)
结构ID;
结构名;//由V型参数集合,由一个字符串'名称'索引
//一个整数,ID
//该V型必须实现'get_id()'和'GET_NAME()'功能
的typedef multi_index_container的<
    五,
    的indexed_by<
        ordered_unique<
            标签< ID>中
            const_mem_fun< W,无符号整型,&安培; W-- :: get_id> >中
        ordered_unique<
            标签<名称&gt ;,
            const_mem_fun< W,标准::字符串,&安培; W-- :: GET_NAME> >
    >
> ni_collection;ni_collection m_collection;
};


解决方案

在阐述@ sehe的回答是:Boost.MultiIndex的predefined键提取自动处理非关联化(例如, const_mem_fun<富,酒吧,&安培;富::酒吧> 可作为是一个的multi_index_container 富*的 S)。您可以利用此功能,并写入以下内容(没有任何用户提供的键提取):

<大骨节病> 住在Coliru

 的#include&LT;升压/ multi_index_container.hpp&GT;
#包括LT&;提升/ multi_index / mem_fun.hpp&GT;
#包括LT&;提升/ multi_index / ordered_index.hpp&GT;
#包括LT&;内存和GT;命名空间BMI =提振:: multi_index;模板&LT; typename的T&GT;
结构remove_pointer {使用类型= T;};模板&LT; typename的T&GT;
结构remove_pointer&LT; T *&GT; {使用类型= T;};模板&LT; typename的T&GT;
结构remove_pointer&LT;的std :: shared_ptr的&LT; T&GT;&GT; {使用类型= T;};模板&LT; typename的V&GT;类集合{
  上市:
    结构ID;
    结构名;    使用W =类型名remove_pointer&LT; V&GT; ::类型;    TYPEDEF提振:: multi_index_container的&LT;
        五,
        BMI ::的indexed_by&LT;
            BMI :: ordered_unique&LT;
                BMI ::标签&lt; ID&gt;中
                BMI :: const_mem_fun&LT; W,无符号整型,&安培; W-- :: get_id&GT;
            &gt;中
            BMI :: ordered_unique&LT;
                BMI ::标签&lt;名称&gt ;,
                BMI :: const_mem_fun&LT; W,常量标准::字符串&功放;,&安培; W-- :: GET_NAME&GT;
            &GT;
        &GT;
    &GT; ni_collection;
};结构演示{
    无符号_id;
    标准::字符串_name;    演示(无符号_id,常量标准::字符串&安培; _name):_ ID(_id)_名(_name){}    无符号get_id()const的{返回_id; }
    标准::字符串常量和放大器; GET_NAME()const的{返回_name; }
};诠释主(){
    收集和LT;演示&GT; :: ni_collection作品{{42,LTUAE},{4,PI}};
    收集和LT;演示* GT; :: ni_collection also_works {新的演示{42,LTUAE},新的演示{4,PI}};
    收藏&LT;的std :: shared_ptr的&LT;演示&GT;&GT; :: ni_collection this_too {性病:: make_shared&LT;演示&GT;(42LTUAE)的std :: make_shared&LT;演示&GT;(4,PI)};
}

唯一棘手的部分是, const_mem_fun 使用是W = 的std :: remove_pointer&LT; V&GT; ::类型(即 V 如果 V 是一个普通的类型或类型它指出,如果它是一个指针)。

编辑:而不是中的std :: remove_pointer&LT; V&GT; ,更新code采用了手工制作的 remove_pointer 模板类部分专业理解 T * 的std :: shared_ptr的&LT; T&GT; ;你可以扩展这个覆盖,例如,的std ::的unique_ptr&LT; T&GT; 或你需要迎合任何其他智能指针类

The answer to this question has general application, but I will motivate it with the following example:

I have the following template class:

template <typename V>
class Collection
{
public:
    struct id{};
    struct name{};
    // A collection parameterized by type V that is indexed by a string 'name'
    // and a integer 'id'
    // The type V must implement 'get_id()' and a 'get_name()' functions
    typedef multi_index_container <
        V,
        indexed_by<
            ordered_unique<
                tag<id>, const_mem_fun<V, unsigned int, &V::get_id> >,
            ordered_unique<
                tag<name>, const_mem_fun<V, std::string, &V::get_name> >
        >
    > ni_collection;
>

I want to modify this template so that I can create a collection with the objects, their pointers or their references: Collection<Obj>, Collection<std::unique_ptr<Obj>> or Collection<Obj *>.

How would I modify my template to achieve this?

--- UPDATE --- I had posted a related question here: Computing The Type Of A Function Pointer

Synthesizing the excellent answers in both places, I have finally achieved my original goal. Here are the details of my current implementation:

template <typename V>
class Collection
{
private:
// A type-level function that returns the undecorated type of the object
// So unrwap_object_type<Widget *> = Widget
//    unwrap_object_type<std::unique_ptr<Widget>> = Widget
//    unwrap_object_type<Widget> = Widget
template<typename T, typename = void>
struct unwrap_object_type { typedef T type; };

template <typename T>
struct unwrap_object_type<T *, void> { typedef T type; };

template<typename T>
struct unwrap_object_type<T,
    typename std::conditional<false,
        typename T::element_type, void>::type>
{
  typedef typename T::element_type type;
};
////

// So that QHNETO_COLLECTION<Widget>, QHNETO_COLLECTION<Widet *>,
// and QHNETO_COLLECTION<std::unique_ptr<Widget>> are valid
typedef typename unwrap_object_type<V>::type W;

// Tags for the two indices (id and name) of the collection
struct id;
struct name;

// A collection parameterized by type V that is indexed by a string 'name'
// and a integer 'id'
// The type V must implement 'get_id()' and a 'get_name()' functions
typedef multi_index_container <
    V,
    indexed_by<
        ordered_unique<
            tag<id>,
            const_mem_fun<W, unsigned int, &W::get_id> >,
        ordered_unique<
            tag<name>,
            const_mem_fun<W, std::string, &W::get_name> >
    >
> ni_collection;

ni_collection m_collection;
};

解决方案

Elaborating on @sehe's answer: Boost.MultiIndex predefined key extractors handle dereferencing automatically (for instance, const_mem_fun<foo,bar,&foo::bar> can be used as is with a multi_index_container of foo*s). You can take advantage of this capability and write the following (without any user-provided key extractor):

Live On Coliru

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <memory>

namespace bmi = boost::multi_index;

template<typename T>
struct remove_pointer{using type=T;};

template<typename T>
struct remove_pointer<T*>{using type=T;};

template<typename T>
struct remove_pointer<std::shared_ptr<T>>{using type=T;};

template <typename V> class Collection {
  public:
    struct id;
    struct name;

    using W=typename remove_pointer<V>::type;

    typedef boost::multi_index_container<
        V,
        bmi::indexed_by<
            bmi::ordered_unique<
                bmi::tag<id>,
                bmi::const_mem_fun<W, unsigned int, &W::get_id>
            >,
            bmi::ordered_unique<
                bmi::tag<name>,
                bmi::const_mem_fun<W,const std::string&, &W::get_name> 
            > 
        >
    > ni_collection;
};

struct Demo {
    unsigned _id;
    std::string _name;

    Demo(unsigned _id,const std::string& _name):_id(_id),_name(_name){}

    unsigned           get_id() const { return _id; }
    std::string const& get_name() const { return _name; }
};

int main() {
    Collection<Demo>::ni_collection works{ { 42, "LTUAE" }, { 4, "PI" } };
    Collection<Demo *>::ni_collection also_works{ new Demo{ 42, "LTUAE" }, new Demo{ 4, "PI" } };
    Collection<std::shared_ptr<Demo>>::ni_collection this_too{ std::make_shared<Demo>( 42, "LTUAE" ), std::make_shared<Demo>( 4, "PI" ) };
}

The only tricky part is that const_mem_fun uses W=std::remove_pointer<V>::type (i.e. V if V is a plain type or the type it points to if it's a pointer).

Edited: Instead of std::remove_pointer<V>, the updated code uses a handcrafted remove_pointer template class partially specialized to understand T* and std::shared_ptr<T>; you can extend this to cover, for instance, std::unique_ptr<T> or any other smart pointer class you need to cater to.

这篇关于C ++:确定类指针类型的,在使用升压多指标的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆