I have a complex problem that can be boiled down to the following deduction guide
template <class R> R return_r() { return R{}; }
void accep_float(float arg) { (void)arg; }
int main() {
accep_float(return_r());
}
Can I put a deduction guide to make the template deduct the right type according to the accepting function, like float
here accep_float(return_type<float>());
?
CodePudding user response:
A templated conversion operator can be used for this kind of "backward" deduction:
struct foo {
template <typename T>
operator T() { return T{};}
};
void accep_float(float arg) { (void)arg; }
int main() {
accep_float(foo{});
}
I am not aware of deduction guides for function templates. Anyhow, you must first call foo{}
(or return_r
in your case) and only then the conversion to some argument type of accep_float
can be done.
CodePudding user response:
This pure backwards deduction is not possible, as far as I know. However, you can figure out the parameter types of any function beforehand, and use that to pass it in manually:
namespace detail {
template<typename R, typename... A>
constexpr auto parameter_types(R(*)(A...)) {
return std::tuple<A...>{};
}
template<typename R, typename... A>
constexpr auto parameter_types(std::function<R(A...)>) {
return std::tuple<A...>{};
}
template<typename C, typename R, typename... A>
constexpr auto parameter_types(R(C::*)(A...)) {
return std::tuple<A...>{};
}
template<typename C, typename R, typename... A>
constexpr auto parameter_types(R(C::*)(A...) const) {
return std::tuple<A...>{};
}
}
template<typename F>
using parameter_types = decltype(detail::parameter_types(std::declval<F>()));
template<typename F>
using first_parameter = std::tuple_element_t<0u, parameter_types<F>>;
and now in main
you can use first_parameter
like this:
int main() {
using R = first_parameter<decltype(accep_float)>;
accep_float(return_r<R>());
}
with this method you can deduce and number of parameters, simple use std::tuple_element_t<N, parameter_types<F>>;
Now it would be neet to make some kind of apply_deduce
function that will call the functions accordingly, however you can't just pass a template function name without naming it's template, therefore defeating the purpose.
Not exactly the most elegant, but since there is no other way, a macro will do the job:
#define apply_deduced(f1, f2) f1(f2<first_parameter<decltype(f1)>>())
int main() {
apply_deduced(accep_float, return_r);
}