There are cases where one uses an always_false
helper to e.g. cause unconditional static_assert
failure if instantiation of some template is attempted:
template <class... T> struct always_false : std::false_type {};
template<class T>
struct UsingThisShouldBeAnError {
static_assert(always_false<T>::value, "You should not use this!");
};
This helper is necessary because a template definition must (at least theoretically) have at least one set of template parameters for which a valid specialization can be produced in order for the program to be well-formed:
[temp.res]/8: The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template [...] and the template is not instantiated, or
[...]
(Writing static_assert(false, "You should not use this!");
above would thus be ill-formed and a compiler could always fire the static assert, even without the template being instantiated, which is not the intention.)
Here is a quick sampling of questions involving this pattern (including further explanation):
Forbids functions with `static_assert`
Are static_asserts to be evaluated if a member template isn't instantiated?
Conditional compilation of templates
It might be useful to have always_false
as a tool in the standard library so we don't have to constantly write it again. However, the answer to the following question makes me wonder whether this is even possible:
Dependent non-type parameter packs: what does the standard say?
There the argument is made (also with respect to [temp.res]/8) that std::enable_if_t<T>
is always either void
or not a type and that it is illegal for anyone to specialize it further. Therefore, a template that relies on the theoretical "specializability" of std::enable_if
to avoid the [temp.res]/8 clause actually causes the program to be ill-formed, no diagnostic required.
Coming back to my question: If the standard provided always_false
, it would have to forbid library users from specializing it as usual (for obvious reasons). But by the above reasoning, that would defeat the whole point of always_false
(namely that it could theoretically be specialized to something other than std::false_type
) - with respect to [temp.res]/8 it would be the same as using std::false_type
directly.
Am I wrong in this reasoning? Or is it actually impossible for the standard library to provide always_false
in a meaningful/useful way (without core language changes)?
In C++20, with lambda, you might do something like:
template <class... T> struct always_false : std::false_type {};
// To have true, but for a type that user code can't reuse as lambda types are unique.
template <> struct always_false<decltype([](){})> : std::true_type{};
To paraphrase Jarod's idea, It could be something like
template <class... T> struct always_false : std::false_type {};
template <> struct always_false</* implementation defined */> : std::true_type{};
Where /* implementation defined */
can be filled by std::_ReservedIdentifer
. User code can't access it, since the identifier is reserved to the library, but there exists a specialization that is true
. That should avoid questions about the ODR and lambdas in specializations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With