In trying to better understand variadic templates, I set myself the task of writing a compile-time type selector based on a given condition (chosen among the ones defined in <type_traits>, e.g. std::is_signed, std::is_floating_point etc.). The selector should pick the first type that meets the condition among those specified as template arguments.
To give you an example:
template<template<typename> class Cond, typename... T>
struct first_if_any {
// some code here
};
first_if_any<std::is_signed, unsigned, long, int>::type a; // long
first_if_any<std::is_unsigned, short, unsigned long, unsigned>::type b; // unsigned long
first_if_any<std::is_floating_point, int, float, double>::type c; // float
These are the features I'd like my selector to have:
- choose the first type if no type meets the condition
- print a user-friendly compilation error if no types are specified
Thus:
first_if_any<std::is_unsigned, long, int>::type a; // long
first_if_any<std::is_arithmetic>::type b; // ERROR
Here's what I came up with (see working example here):
template<template<typename> class Cond, typename... T>
struct first_if_any {
using type = void;
static constexpr bool found = false;
};
template<template<typename> class Cond, typename First, typename... T>
struct first_if_any<Cond, First, T...> {
using type = typename std::conditional<Cond<First>::value || !first_if_any<Cond, T...>::found, First, typename first_if_any<Cond, T...>::type>::type;
static constexpr bool found = Cond<First>::value || first_if_any<Cond, T...>::found;
};
This selects types as expected, and meets requirement 1. Now for my questions:
- How can I meet requirement 2, i.e. generate a user-friendly compile error if someone tries to use the selector without passing types to it?
- Is there a better way to do this (using only standard library features)?
Bonus question, if anyone cares to elaborate:
- Does this qualify as template metaprogramming?
Aucun commentaire:
Enregistrer un commentaire