C++11 标记元组
C++11 元组很好,但它们对我来说有两个巨大的缺点,通过索引访问成员是
C++11 tuples are nice, but they have two huge disadvantages to me, accessing members by index is
- 不可读
- 难以维护(如果我在元组中间添加一个元素,我就完蛋了)
本质上我想要实现的是这个
In essence what I want to achieve is this
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.
相关文章