This question already has answers here:
Static member access in constant expressions
(2 answers)
Closed 3 years ago.
I've discovered that calling a constexpr static method using a constant reference argument leads to an error "expression is not an integral constant" for both clang and icc, but not for gcc or msvc (https://godbolt.org/z/PewOVc):
struct S
{
static constexpr bool ok() { return true; }
};
constexpr void ff(const S &s) // OK for everyone if not a ref
{
static_assert(s.ok(), "oops!"); // ERROR clang/icc, OK gcc/msvc
static_assert(S::ok(), "oops!"); // OK for everyone
}
If argument is not a reference then code compiles by any of these compilers. Who is right/correct here?
The C++ standard disqualifies evaluated id-expressions that have reference types from participating in constant-expressions (unless some more constraints are met, which is not the case for this code).
However gcc seems to ignore this rule. The same result (gcc accepts, clang rejects) can be obtained with this simplified function:
constexpr void ff(const int &s)
{
static_assert((s, true), "oops!");
}
So the problem has nothing to do with static member functions. My interpretation is that this is a gcc bug.
I did not check msvc, maybe the bug is different there but it's still wrong.
Related
I was playing around with constexpr when I found that GCC rejected this seemingly valid code:
#include <functional>
constexpr void test(const std::function<void()>& a) {
a();
}
int main() {
test([](){});
}
I went to godbolt, and clang happens to compile this code fine. Is this a bug in GCC? Here is the godbolt link
As already mentioned in the comments, std::function itself can not be used in constexpr environemt, because the operator()() and also the constructor of std::function is not constexpr.
As this you can use directly a pointer to function, if you have capture less lambdas or you can templatize you function like this in C++20:
constexpr void test(auto&& a) {
a();
}
or with explicit template parameters in older C++ standards.
Use auto or auto& or auto&& as needed to allow temporary lambda, move it in or copy it ( which might be the same after optimizing )
Taken from the comments:
A constexpr function must have at least one set of inputs that are able to be evaluated in a constant expression - otherwise it's ill formed no diagnostic required*
As clang did not report something did not mean it is a clang bug.
This question already has answers here:
What's the difference between constexpr and const?
(10 answers)
Closed 6 years ago.
In the "Exploring C++17 and beyond" presentation by Mike Isaacson at one point (https://youtu.be/-ctgSbEfRxU?t=2907) there is question about writing:
const constexpr ....
vs single const. Mike said that in C++11 constexpr implies const and in C++14 it does not.
Is it true?
I've tried to find prove for that but I couldn't.
I'm not asking about difference between const and constexpr (as a lot of other questions) but about difference in constexpr in two versions of C++ standard.
Consider this piece of code:
struct T {
int x;
constexpr void set(int y) {
x = y;
}
};
constexpr T t = { 42 };
int main() {
t.set(0);
return 0;
}
It should compile in C++14, but give an error in C++11 as if the member function set was declared const. This is because constexpr implies const in C++11, while this is not true anymore in subsequent versions of the standard.
The constexpr keyword guarantees that the object will not be dynamically initialized at runtime. In case of functions, it guarantees that the function can be evaluated at compile-time. In C++11, this was confounded with "being stored in read-only memory", but this was soon recognized as an error.
In C++14, moreover, constexpr functions and members are much more capable. They can modify non-const objects, for instance, so they cannot be implicitly const.
This question already has an answer here:
Why does constexpr static member (of type class) require a definition?
(1 answer)
Closed 7 years ago.
Here is a problem the reason of which is quite obscure to me, but the workaround of which is fortunately quite easy.
Consider the following code (let me call it my main.cpp):
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
return std::min(zero, BAR);
}
};
int main() {
Foo foo;
foo();
}
When I tried to compile it, I got the error:
foobar:~/stackoverflow$ g++ -std=c++11 main.cpp
/tmp/ccjULTPy.o: In function 'Foo::operator()() const':
main.cpp:(.text._ZNK3FooclEv[_ZNK3FooclEv]+0x1a): undefined reference to `Foo::BAR'
collect2: error: ld returned 1 exit status
The same happens (quite obviously) also if I use the following statement:
return std::min(zero, Foo::BAR);
Below a slightly modified version of the example above.
This one compiles with no error, even though I'm still referring to the BAR member:
#include <algorithm>
struct Foo {
static constexpr float BAR = .42;
float operator()() const noexcept {
float zero = .0;
float bar = BAR;
return std::min(zero, bar);
}
};
int main() {
Foo foo;
foo();
}
I didn't succeed in understanding why the latter version compiles fine while the former ends with an error.
As far as I know, both the versions are correct and should compile, but I strongly suspect that I'm missing something important here.
Any suggestion?
Here my compiler's version: g++ (Debian 5.3.1-5) 5.3.1 20160101.
The selected prototype for min is
template<class T>
/* constexpr since C++14 */ const T& min( const T& a, const T& b );
The pertinent point is that it takes the argument by reference, meaning it One-Definition-Rule (ODR)-uses it.
And you never defined it, you only declared it in your class (with an initializer):
static constexpr float BAR = .42;
Which is good enough for copying and otherwise using the value, but not for using it as anything but a prvalue.
See Why does constexpr static member (of type class) require a definition?
Violation of the ODR (whose finer points are fine and voluminuous indeed) need not be diagnosed:
3.2 One definition rule [basic.def.odr]
4 Every program shall contain exactly one definition of every non-inline function or variable that is odr-used
in that program; no diagnostic required. The definition can appear explicitly in the program, it can be found
in the standard or a user-defined library, or (when appropriate) it is implicitly defined (see 12.1, 12.4 and
12.8). An inline function shall be defined in every translation unit in which it is odr-used.
This question already has an answer here:
call of overloaded with ref-qualifiers member function is ambiguous
(1 answer)
Closed 7 years ago.
The following code uses return type deduction (auto) and different methods for L-value and R-value objects. It seems when combining the two, gcc 4.9.2 has problems with overload resolution: "call of overloaded 'f()' is ambiguous".
Is this a bug or just another strange C++ corner case? Clang accepts it as expected.
struct T {
auto f() & {
return int{0};
}
auto f() && {
return string{""};
}
};
void test_it() {
//Calling with L-value object. Fails with "call of overloaded 'f()' is ambiguous").
T t;
int s = t.f();
//Calling with R-value object. Fails with "call of overloaded 'f()' is ambiguous").
string i = T{}.f();
}
The example can be studied using online compilers here:
gcc 4.9.2: http://goo.gl/IE19y8
clang 3.5.1: http://goo.gl/FRbD8Z
It turned out to be a known bug:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60943
struct A {
int a = 0;
constexpr A() { a = 1; }
};
constexpr bool f() {
constexpr A a;
static_assert(a.a == 1, ""); // L1: OK
return a.a == 1;
}
static_assert(f(), ""); // L2: Error, can not modify A::a in constexpr
Online Compiler URL: http://goo.gl/jni6Em
Compiler: clang 3.4 (with -std=c++1y)
System: Linux 3.2
If I delete L2, this code compiles. If I add L2, the compiler complained "modification of object of const-qualified type 'const int' is not allowed in a constant expression". I am not a language lawyer, so I am not sure whether this is true. However, if it is, why compiler didn't complain anything about L1, since it also called A() as constexpr? Is this a bug of clang? Or did I miss anything?
Reference: http://en.cppreference.com/w/cpp/language/constexpr
BTW, if I change "constexpr A a;" to "A a;" (remove constexpr keyword), L1 failed to compile which is expect. However, the compiler didn't complain about L2 anymore.
Online Compiler URL about this: http://goo.gl/AoTzYx
I believe this is just a case of compilers not having caught up to the changes proposed for C++14. Your constexpr constructor satisfies all the conditions listed in ยง7.1.5/4 of N3936. Both gcc and clang fail to compile your code, but for different reasons.
clang complains:
note: modification of object of const-qualified type 'const int' is not allowed in a constant expression
which doesn't make much sense, but reminds me of the C++11 restriction that constexpr member functions are implicitly const (this is a constructor, and that doesn't apply, but the error message is reminiscent of that). This restriction was also lifted for C++14.
gcc's error message is:
error: constexpr constructor does not have empty body
Seems pretty clear that gcc still implements the C++11 rules for constexpr constructors.
Moreover, N3597 lists this example:
struct override_raii {
constexpr override_raii(int &a, int v) : a(a), old(a) {
a = v;
}
constexpr ~override_raii() {
a = old;
}
int &a, old;
};
N3597 was superseded by N3652, which contains the wording found in the current draft. Unfortunately, the earlier example disappears, but, again, nothing in the current wording says you cannot assign values to data members within the body of a constexpr constructor.
Update (2017-10-03)
clang fixed this, but there has been no new release yet: https://bugs.llvm.org/show_bug.cgi?id=19741
(Compiler explorer)