5

I want to write a helper template that checks if a template parameter pack has a common type, i.e., if applying std::common_type to the pack defines a type.

Using std::void_t with SFINAE I came up with the following definition:

template<typename... Types, typename Enable = void>
struct has_common_type : std::false_type
{ };

template<typename... Types>
struct has_common_type<Types..., std::void_t<std::common_type<Types...>::type>> : std::true_type
{ };

This however does not work, because the template parameter pack must be the last parameter. The compiler raises the following error:

error: template parameter pack must be the last template parameter
                        template<typename... Types, typename Enable = void>

How can one go about defining such a template?

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
sakra
  • 62,199
  • 16
  • 168
  • 151
  • 1
    For something decently likely to be standardized soon, you could copy the small implementation of [`is_detected`](http://en.cppreference.com/w/cpp/experimental/is_detected). Then all you need is a `template using has_common_type_test = std::common_type;` for use in the `is_detected` "call". It uses `void_t`, but not directly like this. – chris Mar 12 '17 at 14:03

1 Answers1

8

Option #1

template <typename... Ts>
using has_common_type = std::experimental::is_detected<std::common_type_t, Ts...>;

DEMO


Option #2

template <typename AlwaysVoid, typename... Ts>
struct has_common_type_impl : std::false_type {};

template <typename... Ts>
struct has_common_type_impl<std::void_t<std::common_type_t<Ts...>>, Ts...> : std::true_type {};

template <typename... Ts>
using has_common_type = typename has_common_type_impl<void, Ts...>::type;

DEMO 2

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • I guess, the last line of Option #2 should be: `template constexpr bool has_common_type_v = has_common_type_impl::value;` – dragondreamer Jan 13 '20 at 16:31