Here is a way to package the boilerplate up in one spot for every return type deduction function:
// usual sequence boilerplate:
template<unsigned... s> struct seq { typedef seq<s...> type; };
template<unsigned max, unsigned... s > struct make_seq:make_seq<max-1, max-1, s...> {};
template<unsigned... s> struct make_seq<0, s...>:seq<s...> {};
// RTR object, which wraps a functor F to do return type deduction:
template<template<typename>class F>
struct RTR {
// Stores a `tuple` of arguments, which it forwards to F when cast to anything:
template<typename... Args>
struct worker {
std::tuple<Args...> args;
worker ( Args&&... a ):args(std::forward<Args>(a)...) {}
template<typename T, unsigned... s>
T call(seq<s...>) const {
return F<T>()( std::forward<Args>(std::get<s>(args))... );
}
template<typename T>
operator T() const
{
return call<T>(make_seq<sizeof...(Args)>());
}
};
// Here operator() creates a worker to hold the args and do the actual call to F:
template<typename... Args>
worker<Args...> operator()( Args&&... args ) const {
return {std::forward<Args>(args)...};
}
};
// We cannot pass function templates around, so instead we require stateless functors:
template<typename T>
struct read {
T operator()( std::istream& in ) const {
T x;
in >> x;
return x;
}
};
// and here we introduce reader, a return type deducing wrapper around read:
namespace { RTR<read> reader; }
You'd have to write a lot of return type deducing code for the above boilerplate to be less than the boilerplate for each specific use.