constexpr and std::cout working on function but not in lambda
Asked Answered
S

2

9

Why constexpr does not work with std::cout, but works with printf?

#include <iostream>
constexpr void f() { std::cout << ""; } //error
constexpr void g() { printf(""); } //ok

And why std::cout works with lambdas constexpr?

#include <iostream>
int main () {
    auto h = []() constexpr { std::cout << ""; }; //ok
}
Sphygmograph answered 12/6, 2019 at 18:20 Comment(1)
Used gcc 9.1 on godbolt.orgBish
L
13

Technically, it doesn't work with any of them.

From [dcl.constexr]:

For a constexpr function or constexpr constructor that is neither defaulted nor a template, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression, or, for a constructor, a constant initializer for some object ([basic.start.static]), the program is ill-formed, no diagnostic required.

f() and g() are never constant expressions (neither std::cout << x nor printf() are constexpr functions), so the constexpr declaration is ill-formed. But the compiler isn't required to diagnose this (in this case, it may be easy, but in the general case... not so much). What you're seeing is that your compiler was able to diagnose one problem but not the other.

But they're both wrong.

Lipscomb answered 12/6, 2019 at 18:25 Comment(6)
Ugh stuff like this really grinds my gears. It seems so arcane and hard to spot a bug like this. Meh to it all!Klaus
@LightnessRacesinOrbit Practically speaking, it's really hard to generally diagnose "you marked this constexpr but it's impossible". So it'd be nice if compilers did, but like... it doesn't super matter. It definitely won't compile if you try to use it as a constant expression.Lipscomb
I'm complaining more about the language than about the compilers. It's utterly absurd that such "simple" code could be ill-formed in a manner that's so difficult for a compiler to diagnose, let alone for the programmer!Klaus
@LightnessRacesinOrbit it's harder than hard. It's undecidable. In terms of Turing machines, this is closely related to the Halting Problem. Meh to it all indeed.Jacalynjacamar
@alterigel It's undecidable in general. As the question shows, a diagnostic may be issued in certain cases. But that's my point: some of the most allegedly simple newer features of the language are almost entirely academic in scope and nature (read: a C++ degree required to use them safely)Klaus
@LightnessRacesinOrbit come to think of it, a license to practice (advanced) C++ doesn't sound like a bad ideaJacalynjacamar
U
8

It doesn't. You need to use it to force a compile time error.

constexpr int a = f(), 0; // fails
constexpr int b = g(), 0; // fails

constexpr functions that never produce a constant expression are ill-formed; no diagnostic required. This means that compilers do a best effort check to see if that is the case, but your program already has an error either way. Seems like gcc can't see that printf is not a constant expression. clang errors at the definition.

User answered 12/6, 2019 at 18:25 Comment(5)
Nice use of the comma operator :)Ignorant
And what about the lambda object? Does it have to compile? By what I understood from your answer, no.Bish
@JoãoPaulo It's the same there. It's an error, but compilers don't need to error out.User
What is the significance of the comma(s) in the snippet above? A comma operator expression to enforce evaluation of the lhs?Catullus
@dfri I needed a way to force constant evaluation of the function and since it returns void, I can't assign it to a variable. So I used the comma operator inside the initializer of a constexpr variable so that the function is evaluated at compile time.User

© 2022 - 2024 — McMap. All rights reserved.