Skip to content

Instantly share code, notes, and snippets.

@sekrasoft
Created October 18, 2017 18:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sekrasoft/f5a3107c72334fc6634df8e88c1e9361 to your computer and use it in GitHub Desktop.
Save sekrasoft/f5a3107c72334fc6634df8e88c1e9361 to your computer and use it in GitHub Desktop.
Декомпозиция кортежей без std::tie и C++17

Декомпозиция кортежей в декларативном стиле:

my_tuple t(1, 2.0, 'x'); // кортеж произвольного типа my_tuple
int a; float b; char c;  // переменные, в которые хотим распаковать
decomposed(t) = a, b, c; // присваивание (задом наперёд, т.к. C++ не даёт реализовать "=" снаружи класса,
                         //               самая удачная из возможных "прямая" нотация - std::tie(a, b, c) = ...)

Для работы требуется задать правила декомпозиции (в данном случае - класса my_tuple):

DECOMPOSER_RULE(my_tuple, 0, int,   const my_tuple& t, t.a)
DECOMPOSER_RULE(my_tuple, 1, float, const my_tuple& t, t.b)
DECOMPOSER_RULE(my_tuple, 2, char,  const my_tuple& t, t.c)

Вывод main.cpp:

a=1 b=2 c=x
My IP is 192.168.0.1
#ifndef TUPLE_DECOMPOSER__DECOMPOSED_PP_HPP
#define TUPLE_DECOMPOSER__DECOMPOSED_PP_HPP
#define DECOMPOSER_RULE(tuple_t, field_id, output_type, input, value) \
namespace tuple_decomposer {\
template <> struct tuple_getter<tuple_t, field_id> {\
output_type get(input) { return (value); }\
};\
}
#endif
#ifndef TUPLE_DECOMPOSER__DECOMPOSED_HPP
#define TUPLE_DECOMPOSER__DECOMPOSED_HPP
namespace tuple_decomposer {
// Пользователь должен реализовать tuple_getter для типов,
// которые он хочет использовать.
// tuple_t играет роль кортежа: tuple_t tuple = (field0, field1, field2, ...)
// tuple_getter<tuple_t, 2>().get(tuple) = field2
template <typename tuple_t, int field>
struct tuple_getter {
// надо реализовать T get(const tuple_t&);
};
template <typename tuple_t, int field = 0>
struct tuple_wrapper {
explicit tuple_wrapper(const tuple_t& tuple) : tuple(tuple) {}
template <typename var_t>
tuple_wrapper<tuple_t, field + 1> operator , (var_t& var) const {
var = tuple_getter<tuple_t, field>().get(tuple);
return tuple_wrapper<tuple_t, field + 1>(tuple);
}
private:
const tuple_t& tuple;
};
template <typename tuple_t>
struct tuple_wrapper <tuple_t, 0> {
explicit tuple_wrapper(const tuple_t& tuple) : tuple(tuple) {}
template <typename var_t>
tuple_wrapper<tuple_t, 1> operator = (var_t& var) const {
var = tuple_getter<tuple_t, 0>().get(tuple);
return tuple_wrapper<tuple_t, 1>(tuple);
}
private:
const tuple_t& tuple;
};
template<typename tuple_t>
tuple_wrapper<tuple_t> decomposed (const tuple_t& tuple) {
return tuple_wrapper<tuple_t>(tuple);
}
} // end of tuple_decomposer
#endif
#include "decomposed.hpp"
#include "decomposed-pp.hpp"
#include <iostream>
#include <climits>
struct tuple3 {
int a;
float b;
char c;
};
// tuple3(a, b, c) === кортеж (a, b, c)
namespace tuple_decomposer {
template <> struct tuple_getter<tuple3, 0> {
int get(const tuple3& t) { return t.a; }
};
template <> struct tuple_getter<tuple3, 1> {
float get(const tuple3& t) { return t.b; }
};
template <> struct tuple_getter<tuple3, 2> {
char get(const tuple3& t) { return t.c; }
};
}
// Можно и подсахарить
// DECOMPOSER_RULE(tuple3, 0, int, const tuple3& t, t.a)
// DECOMPOSER_RULE(tuple3, 1, float, const tuple3& t, t.b)
// DECOMPOSER_RULE(tuple3, 2, char, const tuple3& t, t.c)
#define LONG_AS_TUPLE(field, value) \
DECOMPOSER_RULE(long, field, int, long $, value)
extern int long_is_long_enough[CHAR_BIT * sizeof(long) - 32];
// long(a) === кортеж из октетов!
LONG_AS_TUPLE(0, $ >> 24 & 0xff);
LONG_AS_TUPLE(1, $ >> 16 & 0xff);
LONG_AS_TUPLE(2, $ >> 8 & 0xff);
LONG_AS_TUPLE(3, $ & 0xff);
int main() {
tuple3 t3; t3.a = 1; t3.b = 2.0; t3.c = 'x';
long IP = (192 << 24) | (168 << 16) | 1;
using tuple_decomposer::decomposed;
int a; float b; char c;
decomposed(t3) = a, b, c;
std::cout << "a=" << a << " b=" << b << " c=" << c << std::endl;
long o1, o2, o3, o4;
decomposed(IP) = o1, o2, o3, o4;
std::cout << "My IP is " << o1 << '.' << o2 << '.' << o3 << '.' << o4;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment