// primary template handles types that do not support pre-increment:
template< class, class = void >
struct has_pre_increment_member : std::false_type { };
// specialization recognizes types that do support pre-increment:
template< class T >
struct has_pre_increment_member<T,
std::void_t<decltype( ++std::declval<T&>() )>
> : std::true_type { };
template<typename T, typename _ = void>
struct is_container : std::false_type {};
template<typename... Ts>
struct is_container_helper {};
template<typename T>
struct is_container<
T,
std::conditional_t<
false,
is_container_helper<
typename T::value_type,
typename T::size_type,
typename T::allocator_type,
typename T::iterator,
typename T::const_iterator,
decltype(std::declval<T>().size()),
decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
decltype(std::declval<T>().cbegin()),
decltype(std::declval<T>().cend())
>,
void
>
> : public std::true_type {};
#include <iostream>
#include <type_traits>
#include <vector>
template<typename ...>
using to_void = void; // maps everything to void, used in non-evaluated contexts
template<typename T, typename = void>
struct is_container : std::false_type
{};
template<typename T>
struct is_container<T,
to_void<decltype(std::declval<T>().begin()),
decltype(std::declval<T>().end()),
typename T::value_type
>> : std::true_type // will be enabled for iterable objects
{};
template<typename T>
void f(T param, typename std::enable_if<is_container<T>::value>::type* = nullptr)
{
std::cout << "Container\n";
}
template<typename T>
void f(T param, typename std::enable_if<std::is_fundamental<T>::value>::type* = nullptr)
{
std::cout << "Fundamental\n";
}
template<typename T>
void f(T param,
typename std::enable_if<!std::is_fundamental<T>::value>::type* = nullptr,
typename std::enable_if<!is_container<T>::value>::type* = nullptr)
{
std::cout << "Other\n";
}
struct Foo{};
int main()
{
int x{}; // fundamental
std::vector<int> v; // container
Foo s{}; // other
f(x);
f(v);
f(s);
}
namespace detail {
template <class T, class Tuple, std::size_t... I>
constexpr T make_from_tuple_impl( Tuple&& t, std::index_sequence<I...> )
{
static_assert(std::is_constructible_v<T,
decltype(std::get<I>(std::declval<Tuple>()))...>);
return T(std::get<I>(std::forward<Tuple>(t))...);
}
} // namespace detail
template <class T, class Tuple>
constexpr T make_from_tuple( Tuple&& t )
{
return detail::make_from_tuple_impl<T>(std::forward<Tuple>(t),
std::make_index_sequence<std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
}
// before C++17
template<typename T>
std::enable_if_t<std::is_integral<T>::value, std::string> to_str(T t)
{
return std::to_string(t);
}
template<typename T>
std::enable_if_t<!std::is_integral<T>::value, std::string> to_str(T t)
{
return t;
}
// since C++17
template<typename T>
auto to_str17(T t)
{
if constexpr(std::is_integral<T>::value)
return std::to_string(t);
else
return t;
}