C++:使用Boost MultiIndex判断指针类型的class
C++: Determine the class of a pointer type in the use of Boost MultiIndex
这个问题的答案具有普遍的应用性,但我会用下面的例子来激发它:
我有以下模板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;
>
我想修改此模板,以便我可以使用对象、它们的指针或它们的引用创建一个集合:Collection<Obj>
、Collection<std::unique_ptr<Obj>>
或 Collection<Obj *>
。
我将如何修改我的模板以实现此目的?
---更新---
我在这里发布了一个相关问题:
综合两地优秀答案,终于达到了最初的目的。以下是我当前实施的详细信息:
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;
};
您可以使用自定义 key extractor. E.g: Advanced features of Boost.MultiIndex key extractors
For reference elements, consider boost::reference_wrapper
or std::reference_wrapper
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
namespace bmi = boost::multi_index;
template <typename V> class Collection {
struct id_extractor {
typedef unsigned result_type;
template <typename U> result_type operator()(U const&e) const { return e.get_id(); }
template <typename U> result_type operator()(U*e) const { return e->get_id(); }
};
struct name_extractor {
typedef std::string result_type;
template <typename U> result_type const& operator()(U const&e) const { return e.get_name(); }
template <typename U> result_type const& operator()(U*e) const { return e->get_name(); }
};
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 boost::multi_index_container<
V, bmi::indexed_by<bmi::ordered_unique<bmi::tag<id>, name_extractor >,
bmi::ordered_unique<bmi::tag<name>, id_extractor > > >
ni_collection;
};
struct Demo {
unsigned _id;
std::string _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" } };
}
详细说明@sehe 的回答:Boost.MultiIndex 预定义的键提取器自动处理解引用(例如,const_mem_fun<foo,bar,&foo::bar>
可以与 multi_index_container
的 foo*
一起使用).您可以利用此功能并编写以下内容(没有任何 user-provided 密钥提取器):
#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" ) };
}
唯一棘手的部分是 const_mem_fun
使用 W
=std::remove_pointer<V>::type
(即 V
如果 V
是普通类型或它指向的类型如果它是一个指针)。
已编辑: 而不是 std::remove_pointer<V>
,更新后的代码使用手工制作的 remove_pointer
模板 class 部分专门用于理解 T*
和 std::shared_ptr<T>
;您可以扩展它以涵盖例如 std::unique_ptr<T>
或您需要满足的任何其他智能指针 class。
这个问题的答案具有普遍的应用性,但我会用下面的例子来激发它:
我有以下模板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;
>
我想修改此模板,以便我可以使用对象、它们的指针或它们的引用创建一个集合:Collection<Obj>
、Collection<std::unique_ptr<Obj>>
或 Collection<Obj *>
。
我将如何修改我的模板以实现此目的?
---更新---
我在这里发布了一个相关问题:
综合两地优秀答案,终于达到了最初的目的。以下是我当前实施的详细信息:
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;
};
您可以使用自定义 key extractor. E.g: Advanced features of Boost.MultiIndex key extractors
For reference elements, consider
boost::reference_wrapper
orstd::reference_wrapper
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
namespace bmi = boost::multi_index;
template <typename V> class Collection {
struct id_extractor {
typedef unsigned result_type;
template <typename U> result_type operator()(U const&e) const { return e.get_id(); }
template <typename U> result_type operator()(U*e) const { return e->get_id(); }
};
struct name_extractor {
typedef std::string result_type;
template <typename U> result_type const& operator()(U const&e) const { return e.get_name(); }
template <typename U> result_type const& operator()(U*e) const { return e->get_name(); }
};
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 boost::multi_index_container<
V, bmi::indexed_by<bmi::ordered_unique<bmi::tag<id>, name_extractor >,
bmi::ordered_unique<bmi::tag<name>, id_extractor > > >
ni_collection;
};
struct Demo {
unsigned _id;
std::string _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" } };
}
详细说明@sehe 的回答:Boost.MultiIndex 预定义的键提取器自动处理解引用(例如,const_mem_fun<foo,bar,&foo::bar>
可以与 multi_index_container
的 foo*
一起使用).您可以利用此功能并编写以下内容(没有任何 user-provided 密钥提取器):
#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" ) };
}
唯一棘手的部分是 const_mem_fun
使用 W
=std::remove_pointer<V>::type
(即 V
如果 V
是普通类型或它指向的类型如果它是一个指针)。
已编辑: 而不是 std::remove_pointer<V>
,更新后的代码使用手工制作的 remove_pointer
模板 class 部分专门用于理解 T*
和 std::shared_ptr<T>
;您可以扩展它以涵盖例如 std::unique_ptr<T>
或您需要满足的任何其他智能指针 class。