如何实现用户友好的访问器

时间:2014-10-17 15:14:34

标签: c++ templates variadic-templates template-meta-programming

我只是发布代码:

#include <tuple>

namespace primary_protocol
{
    namespace
    {
        typedef uint64_t field_id_t;
        typedef uint64_t field_size_t;
        typedef uint64_t msg_id_t;
        typedef uint64_t msg_size_t;
    }

    struct field_header
    {
        field_id_t _id;
        field_size_t _size;
    };

    static const size_t field_header_sz = sizeof(field_header);

    template<class TFieldType, field_id_t id>
    struct field
    {
    private:
    public:
        field_id_t _id = id;
        field_size_t _size = sizeof(*this);
        TFieldType _value;
    };

    struct message_header
    {
        msg_id_t _id;
        msg_size_t _size;
    };

    static const size_t msg_header_sz = sizeof(message_header);

    template<msg_id_t msg_id, class... TFields>
    struct message
    {
        msg_id_t _id;
        msg_size_t _size = sizeof(*this);

        std::tuple<TFields...> fields;
    };
}

namespace impl
{
    typedef uint64_t field_id_t;
    typedef uint64_t msg_id_t;

    static const size_t field_name_sz = 256;
    static const size_t msg_name_sz = 256;

    typedef primary_protocol::field<field_id_t, 0> field_id_field_t;
    typedef primary_protocol::field<char[field_name_sz], 1> field_name_field_t;
    typedef primary_protocol::field<msg_id_t, 2> msg_id_field_t;
    typedef primary_protocol::field<char[msg_name_sz], 3> msg_name_field_t;

    typedef primary_protocol::message<0, field_id_field_t, field_name_field_t> field_definition_msg_t;
    typedef primary_protocol::message<1, msg_id_field_t, msg_name_field_t> msg_declaration_msg_t;
}

#include <iostream>

#include <string.h>

using namespace std;

int main(int argc, char **argv)
{
    impl::field_definition_msg_t field_def_msg;
    std::get<0>(field_def_msg.fields)._value = 10;
    strcpy(std::get<1>(field_def_msg.fields)._value, "hello");

    cout << std::get<0>(field_def_msg.fields)._value << endl
    << std::get<1>(field_def_msg.fields)._value << endl;
}

我的问题是std::get<0>(field_def_msg.fields)._value = 10形式的主要功能中的访问者。假设field_ref<field_id_field_t>(field_def_msg) = 10中的每个类型都是唯一的,有没有办法实现像tuple这样的东西? (此外,如果它们不是唯一的,可以使用field_ref<field_id_field_t, n>来获取n类型的field_id_field_t字段吗?)

1 个答案:

答案 0 :(得分:3)

如评论中所述,您正在寻找std::get的C ++ 14重载。简化的等效实现(对于C ++ 11)如下所示:

template <typename T, std::size_t counter = 0, typename... A> struct find_;
template <typename T, typename F, typename... Tail, std::size_t counter>
struct find_<T, counter, F, Tail...> : find_<T, counter+1, Tail...> {};
template <typename T, typename... Tail, std::size_t counter>
struct find_<T, counter, T, Tail...> : std::integral_constant<std::size_t, counter> {};

template <typename T, typename... Args>
using find = find_<T, 0, Args...>;

template< class T, class... Types >
constexpr T&& get(std::tuple<Types...>&& t)
{
    return std::get<find<T, Types...>::value>(std::move(t));
}

template< class T, class... Types >
constexpr T const& get(std::tuple<Types...> const& t)
{
    return std::get<find<T, Types...>::value>(t);
}

template< class T, class... Types >
constexpr T& get(std::tuple<Types...>& t)
{
    return std::get<find<T, Types...>::value>(t);
}

Demo。请注意,如果tuple不止一次包含此类型,则无法编译 - 它会选择该类型的第一个对象。