按类型检索可变参数 class 的给定成员
Retrieve given member of variadic class by type
这里是一个递归的class定义:
template<class... T>
class Mgr2
{
};
template<class T, class... args>
class Mgr2<T, args...>
{
Container<T> _container;
Mgr2<args...> _tail;
public:
Mgr2() { };
};
我想执行以下操作:
Mgr2<int, double> mgr;
mgr.get<int>(); // retrieves the Container<int> element
我该怎么做?我尝试做几件事但失败了....一个自由函数也很好,如果 class 定义中有 2 "int" 例如,我不在乎行为是否未定义
谢谢!
这是通过重组 Mgr2
:
来实现的一种方法的草图
template<class T>
struct Leaf {
Container<T> container;
};
template<class... Ts>
struct Mgr2 : Leaf<Ts>... {
template<class T>
Container<T> &get() {
return static_cast<Leaf<T>&>(*this).container;
}
};
实例化 Mgr2
后,重复类型会导致编译时错误。
如果我们想允许重复,或者除了按类型索引之外还允许按整数索引,我们可以在 Leaf
:
中添加一个索引参数
template<std::size_t I, class T>
struct Leaf {
Container<T> container;
};
并调整Mgr2
:
template<class Seq, class...> struct Mgr2_Impl;
template<std::size_t... Is, class... Ts>
struct Mgr2_Impl<std::index_sequence<Is...>, Ts...>
: Leaf<Is, Ts>... { };
template<class... Ts>
struct Mgr2 : Mgr2_Impl<std::index_sequence_for<Ts...>, Ts...> {
private:
template<class T, std::size_t I>
Leaf<I, T>& do_get(Leaf<I, T>& leaf) { return leaf; }
template<std::size_t I, class T>
Leaf<I, T>& do_get(Leaf<I, T>& leaf) { return leaf; }
public:
template<class T>
decltype(auto) get() { return do_get<T>(*this).container; }
template<std::size_t I>
decltype(auto) get() { return do_get<I>(*this).container; }
};
如果您想保留您的原始设计,您可以使用SFINAE 或tag dispatch。显示前者:
template<class U>
std::enable_if_t<std::is_same<U, T>{}, Container<U>&> get(){
return _container;
}
template<class U>
std::enable_if_t<!std::is_same<U, T>{}, Container<U>&> get(){
return _tail.template get<U>();
}
使用 std::tuple
和来自 C++14 的 std::get
:
template<typename... Ts>
class Mgr2
{
private:
std::tuple<Container<Ts>...> _containers;
public:
Mgr2() {};
template <typename T>
const Container<T>& get() const { return std::get<Container<T>>(_containers); }
template <typename T>
Container<T>& get() { return std::get<Container<T>>(_containers); }
};
Demo.
如果你坚持使用 C++11,你可以在 C++11 中编写你自己的 get<T>
。
我只是发现可以像这样轻松完成:
template<class... T>
class CptMgr
{
};
template<class T, class... args>
class CptMgr<T, args...>
{
CptContainer<T> _container;
CptMgr<args...> _tail;
public:
template<class U>
CptContainer<U>& get() { return _tail.get<U>(); };
template<>
CptContainer<T>& get() { return _container; };
}
这里是一个递归的class定义:
template<class... T>
class Mgr2
{
};
template<class T, class... args>
class Mgr2<T, args...>
{
Container<T> _container;
Mgr2<args...> _tail;
public:
Mgr2() { };
};
我想执行以下操作:
Mgr2<int, double> mgr;
mgr.get<int>(); // retrieves the Container<int> element
我该怎么做?我尝试做几件事但失败了....一个自由函数也很好,如果 class 定义中有 2 "int" 例如,我不在乎行为是否未定义
谢谢!
这是通过重组 Mgr2
:
template<class T>
struct Leaf {
Container<T> container;
};
template<class... Ts>
struct Mgr2 : Leaf<Ts>... {
template<class T>
Container<T> &get() {
return static_cast<Leaf<T>&>(*this).container;
}
};
实例化 Mgr2
后,重复类型会导致编译时错误。
如果我们想允许重复,或者除了按类型索引之外还允许按整数索引,我们可以在 Leaf
:
template<std::size_t I, class T>
struct Leaf {
Container<T> container;
};
并调整Mgr2
:
template<class Seq, class...> struct Mgr2_Impl;
template<std::size_t... Is, class... Ts>
struct Mgr2_Impl<std::index_sequence<Is...>, Ts...>
: Leaf<Is, Ts>... { };
template<class... Ts>
struct Mgr2 : Mgr2_Impl<std::index_sequence_for<Ts...>, Ts...> {
private:
template<class T, std::size_t I>
Leaf<I, T>& do_get(Leaf<I, T>& leaf) { return leaf; }
template<std::size_t I, class T>
Leaf<I, T>& do_get(Leaf<I, T>& leaf) { return leaf; }
public:
template<class T>
decltype(auto) get() { return do_get<T>(*this).container; }
template<std::size_t I>
decltype(auto) get() { return do_get<I>(*this).container; }
};
如果您想保留您的原始设计,您可以使用SFINAE 或tag dispatch。显示前者:
template<class U>
std::enable_if_t<std::is_same<U, T>{}, Container<U>&> get(){
return _container;
}
template<class U>
std::enable_if_t<!std::is_same<U, T>{}, Container<U>&> get(){
return _tail.template get<U>();
}
使用 std::tuple
和来自 C++14 的 std::get
:
template<typename... Ts>
class Mgr2
{
private:
std::tuple<Container<Ts>...> _containers;
public:
Mgr2() {};
template <typename T>
const Container<T>& get() const { return std::get<Container<T>>(_containers); }
template <typename T>
Container<T>& get() { return std::get<Container<T>>(_containers); }
};
Demo.
如果你坚持使用 C++11,你可以在 C++11 中编写你自己的 get<T>
。
我只是发现可以像这样轻松完成:
template<class... T>
class CptMgr
{
};
template<class T, class... args>
class CptMgr<T, args...>
{
CptContainer<T> _container;
CptMgr<args...> _tail;
public:
template<class U>
CptContainer<U>& get() { return _tail.get<U>(); };
template<>
CptContainer<T>& get() { return _container; };
}