pack fold expression (c++17 extension) available when building with c++14 - c++

The following code contains a fold expression, which afaiu is a c++17 feature:
template <typename... T> static bool variable_length_or(const T ... v) {
return (v || ...);
}
bool foo () {
return variable_length_or(true, false, true, false);
}
what I find odd is that both g++ and clang++ seem to be fine with it when building with -std=c++14 (compiler-explorer). They do create a warning:
<source>:2:16: warning: pack fold expression is a C++17 extension [-Wc++17-extensions]
return (v || ...);
This somewhat indicates that what I'm writing is not okay before c++17, but the compilation succeeds and the code seems to do what it should. I would've expected the compilation to fail.
Any explanation about why the compiler accepts my fold expression?
(credit where credit is due: I took inspiration from this question, and I could check if all T are bool similar to what is suggested here)

A conforming C++17 compiler has to provide fold expressions. But that's a useful language feature, is it worth actively disabling it just because you're compiling in a previous language mode?
Implementations are allowed to provide extensions, provided that they do not alter the behavior of well-formed programs ([intro.compliance]/8). Fold expressions in pre-C++17 are just such an extension - they're purely additive. So as a question of utility tradeoff between allowing and disallowing fold expressions in C++14 mode, it seems that both gcc and clang decided to lean towards allowing.
Of course, you shouldn't rely on this - if you want to write C++17 code, you should compile in C++17. If you want help relying on it, you can compile with -pedantic-errors:
Give an error whenever the base standard (see -Wpedantic) requires a diagnostic, in some cases where there is undefined behavior at compile-time and in some other cases that do not prevent compilation of programs that are valid according to the standard. This is not equivalent to -Werror=pedantic, since there are errors enabled by this option and not enabled by the latter and vice versa.

If you don't add something as -ansi -pedantic, to impose a strict conformance to the standard, the compilers are free to adopt some extensions or, in this case, elements of the following standard.
-ansi -pedantic are the options I add for g++ and clang++; other compilers can use different options, obviously.
-- EDIT --
As pointed by Barry (thanks!), -ansi is no more useful and is enough -pedantic.
As pointed by Passer By (thanks!), can be useful the use of -pedantic-error to impose an error, and non only a warning, in case of not strictly conformance.

Related

What conditional compilation is needed around C++ attributes?

I'm starting to add [[nodiscard]], [[noreturn]] and [[fallthrough]] to my code base, but I still worry the code might need to be used on an older C++ version.
I'm only worried about g++, clang, and Visual Studio.
To be safe should I make every single usage depend on a version check for the exact version it appeared? Or, do these compilers accept (or does the spec even mandate they accept) any [[attribute]] even if unknown, starting with C++11?
Were these allowed and ignored (or supported) even before C++11? (I ask not what the spec says but what the software actually did.)
#if __cplusplus >= 201703L
#define MyNamespace_NoReturnCPP17 [[noreturn]]
#else
#define MyNamespace_NoReturnCPP17
#endif
(Off subject but if I were on the C++ committee, I'd re-use the case keyword to do the same thing as switch, when followed by (, except it would in effect have an automatic break before each case label. And within the case's block (and nowhere else), fallthrough would be accepted as a keyword, that suppresses that automatic break.)
I note the C++14 spec 7.6.1.5 says behavior is "implemenation-defined" but I'm asking a more practical question about what compilers actually did. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
The C++17 spec 10.6.1.6 says "Any attribute-token that is not recognized by the implementation is ignored." That answers my question for C++17 and newer, but again my question is about earlier compilers. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/n4713.pdf
To be safe should I make every single usage depend on a version check for the exact version it appeared? Or, do these compilers accept (or does the spec even mandate they accept) any [[attribute]] even if unknown, starting with C++11?
I prefer adding version checks for safety although mainstream compilers will throw a warning for unknown attributes.
gcc -Wno-ignored-attributes / -Wattributes
Clang -Wunknown-attributes
MSVC C5030
I'm not sure these warning options(and corresponding behavior) have been added since the first C++11 feature-complete version, so you'd better do some checks.
Were these allowed and ignored (or supported) even before C++11?
Since standard attributes syntax is supported starting from C++11, compilers will have trouble at the parsing stage. Demo

Is this a valid way of performing "Expression SFINAE" in C++03?

In C++11, it is easy to SFINAE on whether or not an expression is valid. As an example, imagine checking if something is streamable:
template <typename T>
auto print_if_possible(std::ostream& os, const T& x)
-> decltype(os << x, void());
print_if_possible will only participate in overload resolution if os << x is a well-formed expression.
live example on godbolt.org
I need to do the same in C++03, and I figured out that sizeof could help (as I needed an unevaluated context for an expression). This is what I came up with:
template <int> struct sfinaer { };
template <typename T>
void print_if_possible(std::ostream& os, const T& x,
sfinaer<sizeof(os << x)>* = NULL);
live example on godbolt.org
It seems that both the latest versions of g++ and clang++ accept the sizeof version with -std=c++03 -Wall -Wextra.
Is the code guaranteed to work as intended in C++03?
Is it correct to conclude that any usage of C++11 expression SFINAE can be backported to C++03 using sfinaer and sizeof?
Expression SFINAE is a bit gray. C++03 basically said nothing on the subject. It neither explicitly banned it nor explicitly allowed it. Contemporary implementations did not permit such constructs because it caused substantial implementation complexity and it's unclear whether it's meant to be allowed, and CWG was at one point leaning towards banning it (see the April, 2003 note) before it eventually reversed course, partially in light of decltype and constexpr that were added to C++11 (see the introduction to N2634).
This also all happened well before CWG started explicitly marking the DR status of issues whose resolutions are meant to apply retroactively.
I think the best advice here is simply "ask your compiler vendor". A compiler that supports expression SFINAE in its C++11 mode is unlikely to tear out that support in C++03 mode (the vendor may treat CWG 339 as a defect report and apply it retroactively, or consider it as an extension). OTOH, a compiler that never supported C++11 is unlikely to invest the substantial costs necessary for expression SFINAE to work (indeed, it did not work in a certain major compiler cough until relatively recently). I also suspect that a place still stuck with an 15-year-old language is unlikely to use the modern toolchains necessary for such support.

Why does `std::unary_function` still compile in c++17?

The std::unary_function feature was deprecated in c++11 and deleted in c++17. But with the c++17 compiler flag, this code still compiles:
struct less_than_7 : std::unary_function<int, bool>
{
bool operator()(int i) const { return i < 7; }
};
Built with g++ -std=c++17 -O0 -Wall -pedantic main.cpp here.
Is a feature deletion optional for a compiler to implement?
Since it's no longer part of the C++17 standard its inclusion in one of your source code files falls into the same category as code that introduces things into std.
In other words, the program behaviour is undefined.
The program working is a manifestation of that undefined behaviour. And perhaps your implementation defines that undefined behaviour. But even so, your code is not portable C++17.
While it's nice to have standards, and multiple versions of those standards, the reality is that different toolchains have different levels of compliance.
This may involve delays implementing new features, delays implementing changes, or delays removing things.
This is simply a case of the latter.
VS 2019 has removed std::unary_function, but neither libstdc++ nor libc++ has yet. That's just how it is!
I'm trying to find the appropriate wording, but implementations do have a lot of leeway in adding extra names to std. That's a major reason why you can't - the two names might clash.
In particular, the existing implementation can have helper classes in std. Thus std::unary_function might have become merely a helper template for this particular implementation.

Is it a conforming compiler extension to treat non-constexpr standard library functions as constexpr?

gcc compiles the following code without warning:
#include <cmath>
struct foo {
static constexpr double a = std::cos(3.);
static constexpr double c = std::exp(3.);
static constexpr double d = std::log(3.);
static constexpr double e1 = std::asin(1.);
static constexpr double h = std::sqrt(.1);
static constexpr double p = std::pow(1.3,-0.75);
};
int main()
{
}
None of the standard library functions used above are constexpr functions, we are allowed to use them where a constant expression is required from both the draft C++11 standard and draft C++14 standard section 7.1.5 [dcl.constexpr]:
[...]If it is initialized by a constructor call, that call shall be a
constant expression (5.19). Otherwise, or if a constexpr specifier is
used in a reference declaration, every full expression that appears in
its initializer shall be a constant expression.[...]
Even when using -std=c++14 -pedantic or -std=c++11 -pedantic no warnings are generated (see it live). Using -fno-builtin produces errors (see it live) which indicates that the builtin version of these standard library functions are being treated as if they where constexpr
While clang does not allow the code with any combination of flags I have tried.
So this is a gcc extension to treat at least some builtin functions as if they were constexpr functions even though the standard does not explicitly require them to be. I would have expected to at least receive a warning in strict conformance mode, is this a conforming extension?
TL;DR
In C++14 this is explicitly not allowed, although in 2011 it appeared like this case would be explicitly allowed. It is unclear if for C++11 this fell under the as-if rule, I don't believe it does since it alters observable behavior but that point was not clarified in the issue I reference below.
Details
The answer to this question has shifted with the evolving status of LWG issue 2013 which opens with:
Suppose that a particular function is not tagged as constexpr in the
standard, but that, in some particular implementation, it is possible
to write it within the constexpr constraints. If an implementer tags
such a function as constexpr, is that a violation of the standard or
is it a conforming extension?
In C++11 it was unclear if the as-if rule permitted this but the orignal proposal would have explicitly allowed it once it was accepted and we can see below in the gcc bug report I reference, this was the assumption made by the gcc team.
The consensus to allow this shifted in 2012 and the proposal changed and in C++14 this is a non-conforming extension. This is reflected in the draft C++14 standard section 17.6.5.6 [constexpr.functions] which says:
[...]An implementation shall not declare any standard library function
signature as constexpr except for those where it is explicitly
required.[..]
and although a strict reading of this seems to leave some wiggle room for treating a builtin implicitly as if it were a constexpr we can see from the following quote in the issue that the intention was to prevent divergence in implementations since identical code could produce different behavior when using SFINAE (emphasis mine):
Some concern expressed when presented to full committee for the vote
to WP status that this issue had been resolved without sufficient
thought of the consequences for diverging library implementations, as
users may use SFINAE to observe different behavior from otherwise
identical code.
We can see from the gcc bug report [C++0x] sinh vs asinh vs constexpr that the team relied on the earlier proposed resolution of LWG 2013 which says:
[...]Additionally, an implementation may declare any function to be
constexpr if that function's definition satisfies the necessary
constraints[...]
when deciding whether this change for the math functions was allowed in strict conformance mode.
As far as I can tell this would become conforming if this we received a warning in strict conformance mode i.e. using -std=c++11 -pedantic or if it was disabled in this mode.
Note, I added a comment to the bug report explaining that the resolution changed since this issue was originally addressed.
Jonathan Wakely pointed out in another question a more recent discussion and it seems likely the gcc bug report will be reopened to address this conformance issue.
What about intrinsics
Compiler intrinsics are not covered by the standard and so as far as I can tell they should be exempt from this rule, so using:
static constexpr double a = __builtin_cos(3.);
should be allowed. This question came up in the bug report and opinion of Daniel Krügler was:
[...]Library functions and other intrinsics can probably be considered as
exceptions, because they are not required to be "explainable" by
normal language rules.

Does any compiler support constexpr yet?

I want to play with constexpr, does any compiler support it yet?
The Apache Stdcxx project has a nice table detailing which C++0x features are supported by which compilers. It's been updated on a regular basis and covers most of the modern C++ compilers.
According to that, only GCC 4.5 supports constexpr (note that that support may be experimental).
Between that list and what has been said in the comments, it appears the answer is "no."
As of July 2011, gcc 4.7 supports constexpr. You need to build it from svn though.
Agreed, g++ 4.5 and 4.6 support the keyword, but ignore the implications. I just compiled a simple factorial program (on both versions using -std=c++0x) with the line:
constexpr fact(int i) { return (i>1) ? fact(i-1)*i : 1; }
and it compiled and ran but when examining the asm source (-S option) it showed the function was called with the parameter instead of being determined by the compiler.
Usage of "constexpr" is really easy. Look at this piece of code:
constexpr int get_five(){
return 5;}
This function returns always 5, so it can be declared with "constexpr" keyword.
But factorial function returns value depending on argument, so its "output" is not always the same.