template<class...Fs>struct overloaded:Fs...{
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs...)->overloaded<Fs...>;
вышеописанное немного сложнее в c ++ 14 , но реализации существуют повсеместно.
namespace details {
struct secret_tag {};
struct secret_result {
template<class...Ts>
secret_tag operator()(Ts&&...) const;
};
template<class F>
using secret_tester = overloaded<std::decay_t<F>, secret_result>;
}
template<class F, class Arg>
using match_arg_exactly = std::integral_constant<
bool,
!std::is_same<
details::secret_tag,
std::result_of_t< details::secret_tester<F>(Arg) >
>{}
>;
теперь мы можем запросить данный объект, еслион может точно соответствовать конкретному аргументу.
template <typename HasIntArgument>
void call_one(int i, float f, std::true_type, const HasIntArgument & hia)
{
hia (i);
}
template <typename HasFloatArgument>
void call_one(int i, float f, std::false_type, const HasFloatArgument& hia)
{
hia (f);
}
template <typename F>
void call_one(int i, float f, const F & hia)
{
call_one( i, f, match_arg_exactly<const F&, int>{}, hia );
}
, и мы используем это:
void call_all (int, float)
{}
template<class F, class...Fs>
void call_all (int i, float f, F const& f0, Fs const&...fs) {
call_one( i, f, f0 );
call_all(i, f, fs...);
}
Тестовый код:
struct float_eater {
void operator()(float x)const{ std::cout<< "float "<<x<<"\n"; }
};
struct int_eater {
void operator()(int x)const{ std::cout<< "int "<<x<<"\n"; }
};
call_all( 42, 3.14, float_eater{}, int_eater{}, int_eater{} );
Живой пример
A c ++ 14 overloaded
- это что-то вроде:
template<class...Fs>
struct overloaded;
template<class F0>
struct overloaded<F0>:F0 {
overloaded(F0 f0):F0(std::move(f0)) {}
using F0::operator();
};
template<class F0, class F1>
struct overloaded<F0, F1>: F0, F1 {
overloaded( F0 f0, F1 f1 ):F0(std::move(f0)), F1(std::move(f1)) {}
using F0::operator();
using F1::operator();
};
template<class F0, class...Fs>
struct overloaded<F0, Fs...>:
overloaded<F0, overloaded<Fs...>>
{
overloaded(F0 f0, Fs...fs):
F0(std::move(f0)),
overloaded<Fs...>( std::move(fs)... )
{}
};
, что, на мой взгляд, достаточно для наших целей.(В более общем случае вы либо создаете двоичное дерево, сбалансированное или нет), и обрабатываете совершенную пересылку и ... и т. Д.