1

Some C++ feature test macros( e.g. __cpp_lib_three_way_comparison ) require header inclusion(e.g. <compare>) to test for them.

This seems very backwards, e.g. maybe I want to include header only when I know it is supported by compiler(more precisely compiler+std lib impl it uses), e.g. let's say I have my_fancy_string_view and I want to typedef it to std::string_view if std::string_view is available, but to detect if std::string_view is available I need to include <string_view>...

Is this just a "bug/oopsie" in design of this feature, or is there a good reason why all feature test macros are not predefined by compiler? My guess is to maybe allow the mixing of STL implementations, e.g. clang on some platforms uses gcc's std lib implementation, but then again I presume compilers know what std lib implementations they use so they can adjust predefined macros.

I know <version> header exists, but that does not help me since it was added only in C++20. It may be nice in 10+ years when my baseline is C++20, but for now it is not that useful.
Also fact that this header was added might suggest that in fact requiring "heavy" includes was a mistake, but I would like to get the expert opinion on this.

P.S. This is proposal that added <version>, but it is very tiny so no details...

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 2
    C++17 has `__has_include` to check if a header exists. – interjay Aug 12 '21 at 15:21
  • You want the *compiler* to predefine all the feature test macros from the *standard library*? Where some of those features are going to be compiler-version based? How would that work for those library features (like, say, three-way-comparison) where the library implementation depends on a language feature? – Barry Aug 12 '21 at 15:26
  • 2
    Including [](https://en.cppreference.com/w/cpp/header/version) only if C++ >= 20 or [](https://en.cppreference.com/w/cpp/header/ciso646) (or perhaps `iso646.h` ) for earlier versions may be an option. – Ted Lyngmo Aug 12 '21 at 15:32
  • @Barry I may be missing something, but compiler knows what std lib it will use, right? So I see no problem with that clang knows that if core language supports <=> std lib will support <=> for std::string if std lib version is over 1.2.3. It is not trivial, but I see no circular dependency here. Only thing that is weird that clang 12 will have different predefined macros depending on what std lib implementation it uses, but I prefer it to current solution. – NoSenseEtAl Aug 12 '21 at 15:34
  • @interjay nice fix, but again only if C++17 is my baseline... but if you make it an anwer I will upvote since it is better than what I assumed is possible(use C++ 20 as basline since it is first C++ to have version header). – NoSenseEtAl Aug 12 '21 at 15:37
  • @NoSenseEtAl: C++20 includes C++17, so if C++20 is your baseline, you have `__has_include`. – Nicol Bolas Aug 12 '21 at 15:41
  • 2
    _compiler knows what std lib it will use, right?_ Actually, no. See, for example, https://stackoverflow.com/questions/14972425/should-i-use-libc-or-libstdc – Paul Sanders Aug 12 '21 at 15:42
  • @NicolBolas I meant that if I have code that "forks" implemention based on language standard/compiler I before assumed C++ 20 is the first standard that makes it easy. But __has_include is in C++17 so that is an improvement. – NoSenseEtAl Aug 12 '21 at 15:43
  • @NoSenseEtAl No it doesn't. And the standard library doesn't know what compiler it will use. The compiler's job is to provide the language and the standard library's job is to provide the library. – Barry Aug 12 '21 at 15:43
  • @PaulSanders but that is configurable with --stdlib ? https://stackoverflow.com/questions/48149688/clang-what-exactly-does-the-stdlib-flag-do – NoSenseEtAl Aug 12 '21 at 15:44
  • 3
    Sure, but I don't think the compiler 'knows' all the detailed differences between `libc++` and `libstdc++`. That would be asking too much. Besides, library developers want to be able to make changes independently of the compiler developers. – Paul Sanders Aug 12 '21 at 15:49
  • @PaulSanders ok, I see your and Barry point: it is to decouple the compiler and std lib impl. Again if you make it a answer I will upvote it, I think it is a good explanation. – NoSenseEtAl Aug 12 '21 at 15:51

2 Answers2

5

but to detect if std::string_view is available I need to include <string_view>...

No, you have to use __has_include(<string_view>) first.

Library features are defined by headers because libraries are defined by headers. The compiler cannot, in most cases, know the contents of a header until it compiles it.

And yes, many parts of the standard library are usable across compilers. While some components are specific to a compiler/platform, it's possible to implement a lot of the standard library without relying on platform/compiler specifics. The standard library, or at least much of it, can be updated independently of the compiler it hooks to.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • "Can be" is a bit weak I think? libc++ and libstdc++ can and do work with the exact same compiler, and often implement different sets of features. "Some standard libraries" might be a stronger statement (as not all standard libraries have multiple compiler support) – Yakk - Adam Nevraumont Aug 13 '21 at 15:21
4

Following on from the comments, an issue to touch on here is that you don't want the compiler to have to know exactly which features are and are not supported by the library implementation(s) it uses.

To do so would require changes to the compiler every time the library is updated, and that would quickly become unmanageable.

To put it another way, it is the job of the library to inform code that uses it what features it supports, and that can only be done via the library's header files.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48