随笔 - C++ 元组的一些应用 (子元组,流式 IO, 运算符重载)

学模板元编程时写的一些玩具

需 C++17 及以上

子元组

tupleSUB.hppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#ifndef TUPLE_SUB_HPP_
#define TUPLE_SUB_HPP_

#include <tuple>
#include <type_traits>

#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>

template <std::size_t Begin, class Tuple, std::size_t... Is>
constexpr auto subtuple_impl_(Tuple &&t, std::index_sequence<Is...>) {
return std::make_tuple(std::get<Is + Begin>(t)...);
}

template <std::size_t Begin, std::size_t Len, class Tuple>
constexpr auto subtuple(Tuple &&t) {
static_assert(Begin <= TPL_SIZE_(Tuple) && Len <= TPL_SIZE_(Tuple) &&
Begin + Len <= TPL_SIZE_(Tuple),
"Out of range");

return subtuple_impl_<Begin>(t, std::make_index_sequence<Len>());
}

template <std::size_t Pos, class Tp, class Tuple>
constexpr auto tuple_push(Tp &&v, Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");

return std::tuple_cat(subtuple<0, Pos>(t),
std::make_tuple(v),
subtuple<Pos, TPL_SIZE_(Tuple) - Pos>(t));
}

template <class Tp, class Tuple>
constexpr auto tuple_push_front(Tp &&v, Tuple &&t) {
return tuple_push<0>(v, t);
}

template <class Tp, class Tuple>
constexpr auto tuple_push_back(Tp &&v, Tuple &&t) {
return tuple_push<TPL_SIZE_(Tuple)>(v, t);
}

template <std::size_t Pos, class Tuple>
constexpr auto tuple_pop(Tuple &&t) {
static_assert(TPL_SIZE_(Tuple) > 0, "Pop from empty tuple");

return std::tuple_cat(subtuple<0, Pos>(t),
subtuple<Pos + 1, TPL_SIZE_(Tuple) - Pos - 1>(t));
}

template <class Tuple>
constexpr auto tuple_pop_front(Tuple &&t) {
return tuple_pop<0>(t);
}

template <class Tuple>
constexpr auto tuple_pop_back(Tuple &&t) {
return tuple_pop<TPL_SIZE_(Tuple) - 1>(t);
}

#undef TPL_SIZE_

#endif

流式 IO

tupleIO.hppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef TUPLE_IO_HPP_
#define TUPLE_IO_HPP_

#include <tuple>
#include <type_traits>
#include <iostream>

template <typename... Ts>
std::istream &operator>>(std::istream &is, std::tuple<Ts...> &p) {
std::apply([&](Ts &...args) { ((is >> args), ...); }, p);
return is;
}

template <typename... Ts>
std::ostream &operator<<(std::ostream &os, std::tuple<Ts...> const &p) {
std::apply(
[&](Ts const &...args) {
std::size_t n{0};
((os << args << (++n != sizeof...(Ts) ? " " : "")), ...);
},
p);
return os;
}

#endif

运算符重载

tupleOO.hppview raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef TUPLE_OO_HPP_
#define TUPLE_OO_HPP_

#include <tuple>
#include <type_traits>

#define TPL_SIZE_(Tuple) std::tuple_size_v<std::remove_reference_t<Tuple>>

template <class Tuple, class BinOp, std::size_t... Is>
constexpr auto
apply2_impl_(BinOp &&f, Tuple &&lhs, Tuple &&rhs, std::index_sequence<Is...>) {
return std::make_tuple(
std::forward<BinOp>(f)(std::get<Is>(lhs), std::get<Is>(rhs))...);
}

template <class Tuple, class BinOp>
constexpr auto apply2(BinOp &&f, Tuple &&lhs, Tuple &&rhs) {
return apply2_impl_(
f, lhs, rhs, std::make_index_sequence<TPL_SIZE_(Tuple)>());
}

#define OO_TUPLE_EQ_(op) \
template <class... Ts> \
constexpr auto operator op(std::tuple<Ts...> const &lhs, \
std::tuple<Ts...> const &rhs) { \
return apply2([](auto &&l, auto &&r) { return l op r; }, lhs, rhs); \
} \
template <class... Ts> \
constexpr auto operator oper##=(std::tuple<Ts...> &lhs, \
const std::tuple<Ts...> &rhs) { \
return lhs = lhs oper rhs; \
}

OO_TUPLE_EQ_(+)
OO_TUPLE_EQ_(-)
OO_TUPLE_EQ_(*)
OO_TUPLE_EQ_(/)
OO_TUPLE_EQ_(%)
OO_TUPLE_EQ_(&)
OO_TUPLE_EQ_(|)
OO_TUPLE_EQ_(^)
OO_TUPLE_EQ_(<<)
OO_TUPLE_EQ_(>>)

#undef OO_TUPLE_EQ_
#undef TPL_SIZE_

#endif