setting c++ standard from target_compile_option goes for higher standard

I recently upgrade my gcc to a version whose default dialect is C++17. Yet, for some specific use cases I’d like to use older standard but with

target_compile_options(${TARGET_NAME} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:cxx_std_14)

I’ve got -std=c++17 appended to the compilation flags.
I had open an related issue a long time ago, which I have since forgotten. If I understand correctly cxx_std_yy means at least version yy.

How can I have exactly version yy, enforcing modern cmake?

AFAIK, you cannot. The best you can do is error in a header if the C++ version is “too new”.

Your bit doesn’t work because cxx_std_14 is a compile feature, not an option. Use:

target_compile_features(${TARGET_NAME} PUBLIC cxx_std_14)

My bad, I actually meant target_compile_features.

Is the behavior the same with the “old way” (in tutorial, langage dialect is directly set from CMAKE variables)? I didn’t test.

It’s a shame. My actual use case is that I write code that might have to be supported by old compiler for which I know, for sure, that the langage standard is limited, yet I don’t have always such a compiler at hand. My code is shipping, sometime, alternate implementation according to the langage level and I would have prefered to test old version through cmake settings, not through #define. I agree it’s probably a matter of state.

Yet giving more than what is asked for is not always a gift… It should be debatable but it can lead to (bad) surprises. An “At least” option should be better. When one is checking a tool or dependency version, he has “==”, “more” or “less” option (in various flavor), hasn’t he?

Yes, however this ends up just setting up update hazards for the future. You end up having to cut a new release just to support new dependencies (that upgrade on their own schedule). If older compilers matter, test them directly in CI. VTK, ParaView, and CMake all have builds that actually use the old compilers instead of relying on new compilers being told “use an older standard”. Bug fixes get backported to old standards in new compilers; it doesn’t meant that old compilers actually work.

1 Like

On second thought, I agree with your counter-argument.

ah, additional question: Is there a way to retrieve the actual dialect used? At least for information purpose, it would be very useful for me to know, for instance, that C++17 has been used instead of a requested C++14, without scanning the issued compiler command line.


The only reliable way is to check the value of the __cplusplus preprocessor definition. Even with a command line, if there is no -std= flag, you’re left with “whatever the default of the compiler is”.

1 Like

Another thought is that I happened to realize that an unexpected standard was used because I saw in my compile line a -std=c++17 while I requested a c++14. As the command line is constructed by CMake it should be it that is adding the option? Isn’t it? In this case there must be some compiler inspection within CMake that helps to get that?


[EDIT] on a minimal example, inspecting CMAKE variable produced during configuration and generation, I found these ones:


Can’t they be used? I don’t know from which point they are available yet.
[EDIT2] They don’t seem to be documented…


Great, thanks,

For my culture, what is the difference with the other one? (so far, I only found them identical).

It looks to be extracted from the try_compile to extract compiler information. It might be a way to detect things like -std=c++17 in the set of default flags. I would just ignore it because it is undocumented and seems to just be used internally as an intermediate value.