Some time ago, we saw how to create a type-dependent expression that is always false. I noted that it feels weird creating a whole new type just to create a fixed false
value.
But maybe we can make it more useful by generalizing it.
template<typename T, typename...> using unconditional_t = T; template<typename T, T v, typename...> inline constexpr T unconditional_v = v;
The unconditional_t
alias template always represents the type T
, and the unconditional_v
variable template always represents the value v
.
template<typename Whatever> void f() { // X is always int using X = unconditional_t<int, Whatever>; // v is always 42 auto v = unconditional_v<int, 42, Whatever>; }
Even though the resulting type or value is always the same, it is nevertheless a dependent type, and therefore the evaluation does not occur until template instantiation.
We can use this to solve our “cannot static_assert(false)
in a discarded statement” problem:
auto lambda = [total](auto op, auto value) mutable { using Op = decltype(op); if constexpr (std::is_same_v<Op, add_tax_t>) { total += total * value; // value is the tax rate return total; } else if constexpr (std::is_same_v<Op, apply_discount_t>) { total -= std::max(value, total); // value is the discount return total; } else { static_assert(unconditional_v<Op, bool, false>, "Don't know what you are asking me to do."); } };
The unconditional_t
generalizes the alias template std::void_t<...>
: Whereas std::void_t<...>
always evaluates to void
, the unconditional_t
lets you pick the type that it resolves to.
template<typename... Types> using void_t = unconditional_t<void, Types...>;
The unconditional_t
also generalizes the template class std::type_identity<T>
: Whereas std::type_identity<T>
takes only one template type parameter, the unconditional_t
lets you pass extra parameters, which are evaluated (for SFINAE) but otherwise ignored.
template<typename T> using type_identity = unconditional_t<T>;
Well Spotted @samlhsamlh
100% agree,
static_assert(unconditional_v<Op, bool, false>
should be:
static_assert(unconditional_v<bool, false, Op>
however, overall excellent and helpful submission – thanks for your valuable and consistent additions to te devblogs @oldnewthing (Raymond Chen)
Hm, unless I’m missing something, I think this line:
should be:
That is, the unused type should be at the end of the template arguments.