Is it possible to implement always_false in the C++ standard library?

痞子三分冷 提交于 2019-12-04 16:30:13

问题


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)?


回答1:


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.




回答2:


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{};


来源:https://stackoverflow.com/questions/57787666/is-it-possible-to-implement-always-false-in-the-c-standard-library

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!