我如何访问可变参数成员?

问题描述 投票:1回答:1
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',但我看不到任何其他成员的访问方法。

c++ c++11 templates variadic-templates
1个回答
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::tuple<...>

[实现如下:

std::get<N>()
测试:

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.