I'd like to be able to create a vector that is a live filter or transform of another vector. For example, given some function link_filter_to and link_transform_to that defines this behaviour,
std::vector<int> a;
std::vector<int> b;
std::vector<int> c;
a.link_transform_to(b, [](int x) {return x * 2;}); // doubled numbers
a.link_filter_to (c, [](int x) {return x % 2;}); // only odd numbers
a.push_back(1);
a.push_back(2);
expected results:
b: 2, 4c: 1
So far the only way I can think of doing this is to wrap the whole std::vector object in a new class, reimplement each function as a wrapper that calls methods / macros to update the linked vectors, and then performs the standard behaviour of the class. For example
template <typename _Tx>
class my_vector
{
using _Filter_function_callback = std::function<bool()>;
template <typename _Vt> using _Transform_callback_t = std::function<_Vt(_Tx)>;
public:
template <typename _Ty>
auto link_transform_to(_Transform_callback_t<_Ty>&& _Pred) -> std::shared_pointer<my_vector<_Ty>>;
auto link_filter_to(_Filter_function_callback&& _Pred) -> std::shared_pointer<my_vector<_Tx>>;
template <typename ..._Valty>
auto push_back(_Valty&&... _Val) -> my_vector&;
// all other methods defined here ie pop_back(), reserve(...), etc...
protected:
std::set<std::shared_pointer<my_vector<std::any>>> _Linked_transformed_containers;
std::set<std::shared_pointer<my_vector<_Tx >>> _Linked_filtered_containers;
private:
template <typename _Tx1>
struct live_transform{std::shared_pointer<my_vector<_Tx1>> transformed_vector; _Transform_callback_t<_Tx1> callback;};
struct live_filter{std::shared_pointer<my_vector<_Tx>> filtered_vector; _Filter_function_callback callback;};
std::vector<_Tx> m_internal;
};
template <typename _Tx>
template <typename ..._Valty>
my_vector::push_back(_Valty&&... _Val)
{
MUTATE_LIVE_LINKS_VERIFY_AND_ADD(push_back, std::forward<_Valty>(_Val)...)
(m_internal.push_back(std::forward<_Valty>(_Val)), ...);
return this;
}
#define MUTATE_LIVE_LINKS(_Pred_name, ...) \
for (const auto& _Live_filter: _Linked_filtered_containers) \
_Live_filter->filtered_vector->_Pred_name(__VA_ARGS__); \
for (const auto& _Live_transform: _Linked_transformed_containers) \
_Live_transform->transformed_vector->_Pred_name(__VA_ARGS__);
#define MUTATE_LIVE_LINKS_VERIFY_AND_ADD(_Pred_name, ...) \
for (const auto& _Live_filter: _Linked_filtered_containers) \
{ \
if (_Live_filter.callback(__VA_ARGS__)) \
_Live_filter->filtered_vector->_Pred_name(__VA_ARGS__); \
} \
for (const auto& _Live_transform: _Linked_transformed_containers) \
_Live_transform->transformed_vector->_Pred_name(__VA_ARGS__);
#define MUTATE_LIVE_LINKS_VERIFY(_Pred_name, ...) \
for (const auto& _Live_filter: _Linked_filtered_containers) \
{ \
if (_Live_filter.callback(__VA_ARGS__)) \
_Live_filter->filtered_vector->_Pred_name(); \
} \
for (const auto& _Live_transform: _Linked_transformed_containers) \
_Live_transform->transformed_vector->_Pred_name(__VA_ARGS__);
MUTATE_LIVE_LINKS: methods likeclear(), where something has to apply to the linked vector, but the filter/transform function doesn't need to be applied.MUTATE_LIVE_LINKS_VERIFY_AND_ADD: methods likepush_back(...)where the element has to be checked against the filter/transform method, and then be mutated into the vector.MUTATE_LIVE_LINKS_VERIFY: methods likepop_back(), where no argument is called, but the element has to conform to the filter to be popped.
These macros would be called by each wrapper method ie push_back(...), pop_back(...), erase(...), etc..., by the wrapper class.
This seems to be a very long and tedious way of achieving this, as every method has to be reimplemented, and it isn't flexible for if I wanted to use a deque for the same thing, because there are different method that would have to be implemented. The transforms don't work yet either, or rather they have only been conceptualized, as I don't think that this is the optimal route to take.
What I would like to achieve is a simple way to create live filter and transform vectors that are bound to another vector, without having to wrap each method of a vector in a wrapper-class.