IIRC there were concerns that __has_feature might not be the
right place to be surfacing these traits.
Right, I took some notes back when I was looking into this and my
findings were:
__has_feature() is intended for standardised language features and
it's prominently user-facing so not really appropriate for trait
primitives whether or not they're feature-complete. Once an
alternative is found we should phase those out.
__has_extension() also suffers from being user-facing, but perhaps
less so.
__has_builtin() would let us automatically list all built-in trait
primitives and I did some work to support that but it wasn't clear
what value this adds so I've put that aside.
Observation: There's no need to list "compatibility-only" or
poorly defined trait primitives in any detection macro because
they only exist for compatibility with MSVC and GCC which use
without checking, with the possible exception of Embarcadero(?).
As you see this is a bit of a tangle. As a way forward the viable
options to provide a feature test for _quality_ type trait
primitives could be one of:
a) A new __has_primitive()
b) Shoehorning into __has_extension() but naming the features more
clearly as primitives: e.g.
__has_extension(primitive_is_constructible)
Another option is recommending people use __is_identifier, which already works for this purpose (because we treat these tokens as keywords), but I'd be against that one since we can't mark a trait as unavailable when it's in a not-fully-working state.
One advantage of sticking with __has_feature or __has_extension is that we don't immediately gain a legacy deprecated interface to support and be unhappy about =) Here's what our documentation says:
"For type trait __X, __has_extension(X) indicates the presence of the type trait primitive in the compiler."
We could stick with that, using the is_ prefix as our indicator that the extension is a type trait (and adding these and any further type traits only to __has_extension and not to __has_feature).
Yes, I think __has_extension() is the way to go.
I wonder however if the feature names need a clearer prefix given that the C++ standard library is considered part of the implementation.
The existing names makes it sound to users as though this makes sense:
#if __has_feature(is_constructible) || __has_extension(is_constructible)
std::is_constructible<T>::value
#else
...
#endif
Some of the traits don't work in general (and support just
enough to get through the MS headers); I don't recall exactly
which ones, though, and I think it was more than just
__is_*_destructible. Alp, do you recall? (Maybe it was the
__is_nothrow_* ones?)
Many of the _is_ ones are sketchy. I cooked up some tests to
compare them against GCC and while compatibility was good, overall
usefulness wasn't clear and some of the results were sketchy. I'll
see if I can dig this up but the results may be lost (wish we had
a wiki to throw stuff like this).
Meanwhile our tests for the trait primitives have inconsistent
coverage and fixing them would be a lot of work. Fortunately the
libc++ test suite has great coverage and it might be possible to
reuse that work..
Marshall, do you think a strategically placed static_assert()
could be added somewhere in your type trait tests to compare
answers from the clang builtin type trait primitives against your
quality library implementations?
Do we advertise support for the __has_* ones? We should stop
doing that if we do -- they're fundamentally broken and pretty
much useless (they exist to support libstdc++ and give wrong
answers in some cases for GCC compatibility). Eventually I
would ilke to make them synonyms for the correct traits, but
I'm concerned that people might be relying on the GCC bugs
that we emulate for them.
My understanding of the Embarcadero usage is that they _DO_ use
the feature detection macros. If this is indeed the case (they
should comment, do we have a contact?) then removing them from
__has_feature() is tantamount to removing them completely. I'm not
at all opposed to that but it should be done after we get the
facts from the original authors.
I'm not sure whether we're talking about the same traits. Just to make sure, I mean __has_trivial_* and __has_nothrow_* (which GCC added a few years ago based on the then-C++0x type traits proposal, which got reworked substantially before C++11).
Oh right. The __has ones have issues like PR16627 and ignoring members with default arguments. For the __is ones, there are various quirks and FIXMEs in SemaExprCXX.cpp which need going through. The newly added primitives not marked incomplete are good for general usage though. We should probably only expose feature checks for the non-quirky ones going on a case by case basis.
Alp.