On 6/4/2015 4:30 PM, Peter Dimov wrote:
Eric Niebler wrote:
I made Meta SFINAE-friendly on a lark and found it useful in practice. (See this thread[*] where Louis and I compared common_type implementations with Meta and Hana.) ... [*] http://lists.boost.org/Archives/boost/2015/03/220446.php
Having a SFINAE-friendly fold helps, but here's my implementation of this challenge.
// common_type
template<class...> struct common_type { using type_not_present = void***[]; };
template<class T> struct common_type<T>: std::decay<T> { };
template<class T1, class T2, class... T> using common_type_impl = common_type<decltype(declval<bool>()? declval<T1>(): declval<T2>()), T...>;
template<class T1, class T2, class...T> struct common_type<T1, T2, T...>: eval_or_default<common_type<>, common_type_impl, T1, T2, T...> { };
#include <iostream> #include <typeinfo>
int main() { std::cout << typeid( common_type<char volatile[], void*, int const[], void*>::type ).name() << std::endl; std::cout << typeid( common_type<char, float, int*, double>::type_not_present ).name() << std::endl; }
where eval_or_default<Def, F, T...> checks is_evaluable<F, T...> (from Bruno Dutra's earlier message) and returns F<T...> if evaluable, Def if not.
Getting it right was a bit tricky, but I find the final result quite readable. (This implements the specification in the latest C++17 draft.)
I'm not so sure. If a user defines a specialization for common_type<MyInt, int>, it won't get used when computing common_type<MyInt, int, int>. I think that would complicate your implementation somewhat. I like the mutual recursion between common_type and common_type_impl, but really you've just implemented fold, and it would be better to have fold as a separate reusable algorithm. I see that you've isolated the SFINAE-friendliness in your library to the eval_or_default utility. It's an interesting choice, but I think it's why you can't use a fold here, am I right? -- Eric Niebler Boost.org http://www.boost.org