我如何访问可变成员?

时间:2014-09-17 13:20:35

标签: c++ c++11

template<typename... Types>
struct Foo;

template<typename T , typename... Types>
struct Foo<T, Types ...> : public Foo<Types ...>
{
    Foo( T member , Types ... others ) : Foo<Types ...>( others... ), m_member( member )
    {
    }

    T   m_member;
};

template<typename T>
struct Foo<T>
{
    Foo( T member ) : m_member( member )
    {
    }

    T   m_member;
};

int main()
{
  Foo<char,int,bool,double> f( 'a' , 42 , true , 1.234 );
}

我在SO的某个地方找到了这个代码,我想知道它是否完全没用?在我看来,所有成员都被称为m_member所以我如何访问它们?

如果我cout << f.m_member;它会打印'a',但我认为无法访问其他成员。

1 个答案:

答案 0 :(得分:2)

在您当前的实现中,每个派生的Foo类都会隐藏其父级m_member。由您决定如何实现访问每个字段的逻辑(通过索引,类型,其他)。

一种可能性是通过带有类型或索引的重载模板化成员函数来访问它们(为简单起见,反过来):

#include <type_traits>
#include <cstddef>

template <typename... Types>
struct Foo;

template <typename T, typename... Types>
struct Foo<T, Types...> : Foo<Types...>
{
    // bring get() member functions from parent class into current scope
    using Foo<Types...>::get;

    Foo(T member, Types... others) : Foo<Types...>{others...}, m_member{member} {}

    template <typename U>
    auto get(T* = nullptr)
        -> typename std::enable_if<std::is_same<U, T>::value, T&>::type
    {
        return m_member;
    }

    template <std::size_t N>
    auto get(T* = nullptr)
        -> typename std::enable_if<N == sizeof...(Types), T&>::type
    {
        return m_member;
    }

private:
    T m_member;
};

template <typename T>
struct Foo<T>
{
    Foo(T member) : m_member{member} {}

    template <typename U>
    auto get(T* = nullptr)
        -> typename std::enable_if<std::is_same<U, T>::value, T&>::type
    {
        return m_member;
    }

    template <std::size_t N>
    auto get(T* = nullptr)
        -> typename std::enable_if<N == 0, T&>::type
    {
        return m_member;
    }

private:
    T m_member;
};

试验:

Foo<char, int, bool, double> a{ 'a', 42, true, 1.234 };

assert('a' == a.get<char>());
assert(42 == a.get<int>());

assert(true == a.get<1>());
assert(42 == a.get<2>());

a.get<char>() = 'b';
assert('b' == a.get<3>());

DEMO

对于提供成员访问权限的其他实现,请参阅std::tuple<...>及其std::get<N>()

规范实现如下所示:

#include <type_traits>
#include <cstddef>

template <typename... Types>
struct Foo;

template <typename T, typename... Types>
struct Foo<T, Types...> : Foo<Types...>
{
    Foo(T member, Types... others) : Foo<Types...>{others...}, m_member{member} {}
    T m_member;
};

template <typename T>
struct Foo<T>
{
    Foo(T member) : m_member{member} {}
    T m_member;
};

template <std::size_t N, typename T>
struct element;

template <typename T, typename... Types>
struct element<0, Foo<T, Types...>> 
{
    using type = T;
};

template <std::size_t N, typename T, typename... Types>
struct element<N, Foo<T, Types...>> 
{
    using type = typename element<N - 1, Foo<Types...>>::type;
};

template <std::size_t N, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
    -> typename std::enable_if<N == 0, T&>::type
{
    return f.m_member;
}

template <std::size_t N, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
    -> typename std::enable_if<N != 0
                              , typename element<N, Foo<T, Types...>>::type&
                              >::type
{
    Foo<Types...>& p = f;
    return get<N - 1>(p);
}

template <typename U, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
    -> typename std::enable_if<std::is_same<T, U>::value, T&>::type
{
    return f.m_member;
}

template <typename U, typename T, typename... Types>
auto get(Foo<T, Types...>& f)
    -> typename std::enable_if<!std::is_same<T, U>::value, U&>::type
{
    Foo<Types...>& p = f;
    return get<U>(p);
}

试验:

Foo<char, int, bool, double> a{ 'a', 42, true, 1.234 };

assert(true == get<2>(a));
assert(42 == get<int>(a));

get<char>(a) = 'b';
assert('b' == get<0>(a));

DEMO 2