C ++ 11标记元组 [英] C++11 Tagged Tuple
问题描述
C ++ 11元组很好,但是它们对我有两个巨大的缺点,按索引访问成员是
C++11 tuples are nice, but they have two huge disadvantages to me, accessing members by index is
- 不可读
- 难以维护(如果我在元组中间添加元素,则会被拧)
本质上我想要实现的是
tagged_tuple <name, std::string, age, int, email, std::string> get_record (); {/*...*/}
// And then soomewhere else
std::cout << "Age: " << get_record().get <age> () << std::endl;
在boost :: property_map中实现了类似的(类型标记),但是我无法得到转到如何在具有任意数量元素的元组中实现它
Something similar (type tagging) is implemented in boost::property_map, but I ca'nt get my head around how to implement it in a tuple with arbitary number of elements
PS
请不要不建议使用元组定义枚举元素索引。
PS Please do not suggest defining an enum with tuple element indices.
UPD
好,这是一种动机。在我的项目中,我需要能够即时定义许多不同的元组,并且所有这些元组都必须具有某些特定的功能和运算符。
UPD OK, here is a motivation. In my projects I need to be able to define lots of different tuples 'on-the-fly' and all of them need to have certain common functions and operators. This is not possible to achieve with structs
UPD2
实际上,我的示例可能不太现实。
UPD2 Actually my example is probably a bit unrealistic to implement. How about this?
tagged_tuple <tag<name, std::string>, tag<age, int>, tag<email, std::string>> get_record (); {/*...*/}
// And then somewhere else
std::cout << "Age: " << get_record().get <age> () << std::endl;
推荐答案
我不知道任何现有的类这样,但是使用 std :: tuple
和索引类型列表将内容放在一起很容易:
I'm not aware of any existing class that does this, but it's fairly easy to throw something together using a std::tuple
and an indexing typelist:
#include <tuple>
#include <iostream>
template<typename... Ts> struct typelist {
template<typename T> using prepend = typelist<T, Ts...>;
};
template<typename T, typename... Ts> struct index;
template<typename T, typename... Ts> struct index<T, T, Ts...>:
std::integral_constant<int, 0> {};
template<typename T, typename U, typename... Ts> struct index<T, U, Ts...>:
std::integral_constant<int, index<T, Ts...>::value + 1> {};
template<int n, typename... Ts> struct nth_impl;
template<typename T, typename... Ts> struct nth_impl<0, T, Ts...> {
using type = T; };
template<int n, typename T, typename... Ts> struct nth_impl<n, T, Ts...> {
using type = typename nth_impl<n - 1, Ts...>::type; };
template<int n, typename... Ts> using nth = typename nth_impl<n, Ts...>::type;
template<int n, int m, typename... Ts> struct extract_impl;
template<int n, int m, typename T, typename... Ts>
struct extract_impl<n, m, T, Ts...>: extract_impl<n, m - 1, Ts...> {};
template<int n, typename T, typename... Ts>
struct extract_impl<n, 0, T, Ts...> { using types = typename
extract_impl<n, n - 1, Ts...>::types::template prepend<T>; };
template<int n, int m> struct extract_impl<n, m> {
using types = typelist<>; };
template<int n, int m, typename... Ts> using extract = typename
extract_impl<n, m, Ts...>::types;
template<typename S, typename T> struct tt_impl;
template<typename... Ss, typename... Ts>
struct tt_impl<typelist<Ss...>, typelist<Ts...>>:
public std::tuple<Ts...> {
template<typename... Args> tt_impl(Args &&...args):
std::tuple<Ts...>(std::forward<Args>(args)...) {}
template<typename S> nth<index<S, Ss...>::value, Ts...> get() {
return std::get<index<S, Ss...>::value>(*this); }
};
template<typename... Ts> struct tagged_tuple:
tt_impl<extract<2, 0, Ts...>, extract<2, 1, Ts...>> {
template<typename... Args> tagged_tuple(Args &&...args):
tt_impl<extract<2, 0, Ts...>, extract<2, 1, Ts...>>(
std::forward<Args>(args)...) {}
};
struct name {};
struct age {};
struct email {};
tagged_tuple<name, std::string, age, int, email, std::string> get_record() {
return { "Bob", 32, "bob@bob.bob"};
}
int main() {
std::cout << "Age: " << get_record().get<age>() << std::endl;
}
您可能会想编写 const
和右值 get
访问器在现有访问器的顶部。
You'll probably want to write const
and rvalue get
accessors on top of the existing one.
这篇关于C ++ 11标记元组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!