按类型检索可变类的给定成员

Retrieve given member of variadic class by type

本文关键字:成员 类型 检索      更新时间:2023-10-16

这是一个递归类定义:

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

我怎么能这么做?我试着做几件事,但失败了....自由函数也很好,如果在类定义中有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或标签调度。显示前者:

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, std::get from c++ 14:

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); }
};

演示。

如果你坚持使用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; };
}