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 63 64 65 66 67 68 69 70 71 72 73 74 75
|
#include <type_traits>
#include <iostream>
#include <tuple>
#include <string>
#include <vector>
template<typename T, typename F, template<typename> class Tester>
struct ReflectiveOperator
{
static constexpr size_t TerminalCase = std::tuple_size<std::decay_t<T>>::value - 1;
template<size_t Index>
static std::enable_if_t<Index != TerminalCase, size_t> Op(T&& tuple, const F& func)
{
return PerformOp<Index>(std::forward<T>(tuple), func) + Op<Index + 1>(std::forward<T>(tuple), func);
}
template<size_t Index>
static std::enable_if_t<Index == TerminalCase, size_t> Op(T&& tuple, const F& func)
{
return PerformOp<TerminalCase>(std::forward<T>(tuple), func);
}
private:
template<size_t Index>
static std::enable_if_t<Tester<decltype(std::get<Index>(std::declval< T >()))>::value, size_t> PerformOp(T&& tuple, const F& func)
{
func(std::get<Index>(std::forward<T>(tuple)));
return 1; //1 field was changed
}
template<size_t, typename... Args>
static size_t PerformOp(Args&&...) { return 0; }
};
template<typename T, typename F>
static size_t ReflectiveOperation(T&& tuple, const F& func)
{
return ReflectiveOperator<T, F, DefaultTester>::template Op<0>(std::forward<T>(tuple), func);
}
template<template<typename> class Tester, typename T, typename F>
static size_t SelectiveReflectiveOperation(T&& tuple, const F& func)
{
return ReflectiveOperator<T, F, Tester>::template Op<0>(std::forward<T>(tuple), func);
}
#define TestType(Name, X) template<typename T> \
class Name \
{ \
template<typename = decltype(X)> \
static constexpr bool test(int) { return true; } \
static constexpr bool test(...) { return false; } \
public: \
constexpr static bool value = test(int()); \
};
TestType(DefaultTester, int());
TestType(CanDivideByInt, std::declval<T>() /= int());
TestType(CanCout, std::cout << std::declval<T>());
TestType(TripleIt, std::declval<T>() = std::declval<T>() + std::declval<T>() + std::declval<T>());
int main()
{
std::tuple<double, int, char, std::string, const float, std::vector<int>> tuple{ 11, 22, '!' * 2, "hello", 0.2f, { 7 } };
size_t numberChanged = SelectiveReflectiveOperation<CanDivideByInt>(tuple, [](auto& x) { x /= 2; });
SelectiveReflectiveOperation<CanDivideByInt>(const_cast<const decltype(tuple)&>(tuple), [](auto& x) { x /= 2; }); //does nothing
std::cout << "Number of changes: " << numberChanged << std::endl;
SelectiveReflectiveOperation<CanCout>(tuple, [](auto& x) { std::cout << x << ' '; });
std::cout << std::endl << "Sizes: ";
ReflectiveOperation(tuple, [](auto& x) { std::cout << sizeof(x) << ' '; });
numberChanged = SelectiveReflectiveOperation<TripleIt>(tuple, [](auto& x) { x = x + x + x; });
std::cout << std::endl << "Number of changes: " << numberChanged << std::endl;
SelectiveReflectiveOperation<CanCout>(tuple, [](auto& x) { std::cout << x << ' '; });
}
|