Jonathan Wakely wrote:
Anecdata: I often do tag dispatching on traits and overload a function to take either std::true_type or std::false_type, where I know the trait is guaranteed to derive from one or the other (which is true for all the standard type traits, and others that I write).
That's indeed a guarantee the standard gives, and since it's a "shall" in the blanket requirements, user specializations also have to obey (were they allowed). I don't like it very much, though. It's just to save some typing - you could write integral_constant<bool, trait<>::value> when you need the guaranteed integral_constant. And the price is that everyone specializing a trait must now #include whatever defines integral_constant. As a general rule, a library that offers a customization point should make it possible for that customization point to be activated without including any library headers. Otherwise, it all becomes a tangled mess with everyone including the serialization library, the type traits library, the hash library, and who knows what else. I do realize that you're talking about what people actually do, though, and I agree that it is very likely that some of them do tag dispatching on mpl::true_ and mpl::false_. In fact, I think that I remember code in Boost doing just that.
Would it be possible to define true_ and false_ with a lot less code?
Possibly. The problem is that mpl::bool_ is owned by MPL. It can impose all sorts of (potentially changing, although this is not an issue at the moment) requirements on them. None of those are actually needed by people doing tag dispatching, but we can't just kidnap mpl::true_ and mpl::false_ and decree that they shall henceforth live in Core.