Мой предыдущий ответ, не учитывал необходимость переупорядочивания.
Здесь, порядок учтен.
boost - не используется. boost::mpl мог бы использоваться для реализации, is_tuple_of_unique_types, но этот тип и так достаточно компактен.
struct Operation {
int (*ops1)();
int (*ops2)(int);
};
// метаданные своими руками
template<typename T>
constexpr auto memeber_ptrs_tuple = nullptr;
template<>
constexpr auto memeber_ptrs_tuple<Operation> = std::make_tuple(
& Operation::ops1,
& Operation::ops2
);
// Библиотека
namespace ditails
{
template< typename ... T>
constexpr bool is_unique_types=false;
template< typename T0 >
constexpr bool is_unique_types<T0> = true;
template< typename T0, typename T1, typename... Tx >
constexpr bool is_unique_types<T0,T1,Tx...>
= is_unique_types<T0,Tx...> && is_unique_types<T0,Tx...>
&& ! std::is_same<T0,T1>::value;
template< typename T>
constexpr bool tuple_of_unique_types=false;
template< typename...T>
constexpr bool tuple_of_unique_types<std::tuple<T...>> = is_unique_types<T...>;
template< typename T>
struct impl_reorder_tuple_cast;
template< typename... T>
struct impl_reorder_tuple_cast<std::tuple<T...>>
{
template<typename Tuple>
constexpr static std::tuple<T...> call(Tuple tuple)
{
return { std::get<T>(tuple) ... }; // именно эта строчка занимается переупорядочисванием.
}
};
template<typename Result, typename Input>
constexpr Result reorder_tuple_cast( Input input )
{
static_assert( tuple_of_unique_types<Result> );
static_assert( tuple_of_unique_types<Input> );
static_assert( std::tuple_size_v<Result> == std::tuple_size_v<Input> );
return impl_reorder_tuple_cast<Result>::call(input);
}
template<typename Result, typename ... T>
constexpr Result make_from_tuple( std::tuple<T...> tuple )
{
return Result{ std::get<T>(tuple)... };
}
template< typename T, typename... MemPtrs >
constexpr auto to_tuple( T& obj, const std::tuple<MemPtrs...>& mem_ptrs )
{
return std::make_tuple( (obj.*std::get<MemPtrs>(mem_ptrs))... );
}
template< typename T >
constexpr auto to_tuple( T& obj )
{
return to_tuple(obj, memeber_ptrs_tuple< std::remove_cv_t<T> > );
}
template< typename T, typename... MemPtrs >
constexpr auto to_tie( T& obj, const std::tuple<MemPtrs...>& mem_ptrs )
{
return std::tie( (obj.*std::get<MemPtrs>(mem_ptrs))... );
}
template< typename T >
constexpr auto to_tie( T& obj )
{
return to_tie(obj, memeber_ptrs_tuple< std::remove_cv_t<T> > );
}
template<typename T>
using memebers_tuple_t = decltype( to_tuple( std::declval<T&>() ) );
template<typename Result, typename ... T>
constexpr Result make_from_reordered_args(T...args )
{
static_assert( is_unique_types<T...> );
return make_from_tuple<Result>( reorder_tuple_cast< memebers_tuple_t<Result> >(std::make_tuple(args...) ) );
}
}
using ditails::make_from_reordered_args;
// использование
template<auto... Ops>
class Example {
public:
private:
static constexpr Operation m_ops = make_from_reordered_args<Operation>( Ops... );
};
int o0() { return 42; }
int o1(int i) { return i+2; }
int o2(int i, int j) { return i+j; }
int o1d(double i) { return (int)i+2; }
Example<&o1, &o0> ex; // ok
Example<&o0, &o1> ex2;// ok
Example<&o1, &o1> ex3;// cause error
Example<&o1> ex4;// cause error
Example<&o1, &o2> ex5;// cause error