The following program is failing when compiling with Clang with error: constexpr variable 'struct2Var' must be initialized by a constant expression {var, 2100433}
.
If I remove __attribute__((weak)) from "var" declaration, it is passing without any issues.
Can somebody please explain the theory/reason behind this error.
struct myStruct
{
public:
constexpr operator const wchar_t*() const
{
return &m_cch;
}
const wchar_t m_cch;
};
extern __attribute__((weak)) const constexpr myStruct var {'a'};
struct myStruct2
{
const wchar_t* stzKey = nullptr;
int intvar = 0;
};
static constexpr const myStruct2 struct2Var[1]
{
{var, 2100433}
};
It looks like using __attribute__((weak)) discards the constexpr qualifier with clang but not with gcc. Despite clang trying to be a drop in replacement for gcc, it might implement such non standard feature differently. In that case, I would say that neither gcc nor clang is wrong.
Also, global constexpr might be tricky to maintain as they should all be defined consistently in every translation unit. To face this issue, inline variable have been added to c++17.
Related
case1:
#include <string>
inline constexpr std::string test(std::string s) noexcept
{
return s + "xxx";
}
int main()
{
auto s = test("abc");
}
c++20 with gcc 12.1 is built okay, c++17 with gcc 12.1 or c++20/17 with gcc 11.1 was failed,
constexpr std::string, Is this a new feature, or what does this mean?
case2:
#include <string>
int main()
{
constexpr std::string test{"xxxxxx"};
}
And in this case both failed, what is the difference between these two cases.
There are two different use cases of constexpr here:
constexpr functions
constexpr objects
When you see it on a function such as
inline constexpr std::string test(std::string s) noexcept
{
return s + "xxx";
}
the constexpr is not part of the return type, in the same way that inline is not part of the return type; it is part of the function definition. In this case, constexpr says "this function can possibly be run at compile time".
The second use case you've mentioned is tagging an object definition as constexpr. In this use case, you're telling the compiler that this must be a compile time constant, and currently std::string objects cannot be marked constexpr due to the dynamic memory allocation that it does which it performed at runtime.
One thing you may have seen is that the std::string constructor was marked constexpr in C++20. This does not mean that you can create constexpr instances of std::string. It just means that std::string can be constructed and used within constexpr contexts (like a constexpr function).
You may then ask "if std::string requires runtime allocation, how can it be used within a constexpr function?". The basic answer is that the compiler uses a different allocation strategy to enable it, and does extra magic to make sure no undefined behaviour occurs. You can see more info here.
To give a bit more information about constexpr functions, note that I said it could "possibly" be run at compile time. A function marked constexpr can be run at either compile time or runtime, depending on the arguments it's called with
constexpr int double_val(int x) { return 2 * x; }
int main() {
const int y = double_val(4); // likely ran at compile time
int input = 0;
std::cin >> input;
const int z = double_val(input); // run at runtime
}
If you want to force the function to only run at compile time, that's what C++20's consteval keyword allows you to do.
consteval int double_val(int x) { return 2 * x; }
int main() {
const int y = double_val(4); // fine, ran at compile time
int input = 0;
std::cin >> input;
const int z = double_val(input); // ERROR, could not compile
}
The following might not compile either, for you:
constexpr auto s = test("abc");
There's a slight semantical difference between a constexpr object and a constexpr function.
A constexpr object must be a compile-time constant.
A constexpr function might be a compile-time constant if everything in the function is a constant expression. Subsequently, the result of the function is a constant expression if its parameters are, and obviously not if they're not.
What appears to be happening is that your compiler hasn't yet implemented the constexpr version of the std::string constructor in C++20, but has implemented the constexpr + operator.
Hence the function gets compiled without a constant expression as its parameter, but since its result is not assigned to a constexpr object this is not immediately apparent.
But assigning the function's result to a constexpr reveals the ugly truth.
As the keyword constexpr implies const and it can also be calculated at compile time, does it mean that now declaring variables as const doesn't make sense and we should always declare them as constexpr?
and it can also be calculated at compile time, does it mean that now declaring variables as const doesn't make sense and we should always declare them as constexpr?
And must be calculated at compile time (ignoring the as-if rule).
So you can't declare constexpr a variable initialized with a run-time known value. But you can declare it const.
For example: you can't declare bar constexpr
int foo;
std::cin >> foo;
constexpr int bar = foo; // compilation error
but you can declare it const
int foo;
std::cin >> foo;
const int bar = foo; // compile
No, not at all.
constexpr means "constant expression", as in [possibly] statically-known, as in "[possibly] known at compile time".
const means "cannot be changed after initialisation".
These are completely separate concepts. A const object can be initialised with a runtime value, for example.
constexpr can imply const, but const certainly does not imply constexpr.
(I think constexpr is a very confusing name, due to this.)
Adding to #max66 answer: constexpr can only replace a top-level const. It can never replace pointer-to-const or const reference. So, sometimes constexpr and const can be used in the same declaration. E.g.
const char* const s = "Hello";
can be replaced with:
constexpr const char* s = "Hello";
I need to have volatile member function in my class (which is trivial and has standard layout), so that class instances can be declared volatile (needed for memory-mapped register access).
However, I found that GCC is not willing to call static constexpr functions from volatile members. clang is just fine with that.
Here is the simplified code example:
https://gcc.godbolt.org/z/36rE7h
#include <cstddef>
#include <cstdint>
class B {
public:
static constexpr uint32_t genMask()
{
return 0xFF;
}
uint32_t get(size_t word) const volatile
{
constexpr uint32_t mask = genMask();
return data[word] & mask;
}
private:
uint32_t data[5];
};
uint32_t fun()
{
constexpr uint32_t my_mmio_reg_addr = 0x8000BEEF;
volatile B *b = new (reinterpret_cast<uint32_t *>(my_mmio_reg_addr)) B;
return b->get(0);
}
GCC complains with
In member function 'uint32_t B::get(size_t) const volatile':
13:43: error: 'this' is not a constant expression
13 | constexpr uint32_t mask = genMask();
| ^
If I change
constexpr uint32_t mask = genMask();
with
constexpr volatile uint32_t mask = genMask();
GCC compiles code just fine, but then it treats mask as volatile, always re-reading it's value resulting in non-optimal code.
Why volatile member specifier affects local constexpr variables and static constexpr member functions? Is it a bug in GCC or some dark side of C++ spec?
Why *this is somehow involved here, if it's only local variables and static member function involved?
It turns out to be already known GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80456
According to my testing issue appeared in GCC 4.9 for the first time and is not fix as of GCC 10.2.
Unfortunately, there is no fix for it yet in trunk as well.
consider a class with a constant member:
class foo {
public:
const static int N;
};
foo::N needs to initialized:
constexpr int foo::N = 5;
and note how using the constexpr qualifier instead of const here seems like a mistake.
but GCC, Clang and MSVC all compile just fine!
is there something in the language that allows changing qualifiers here?
is it an error overlooked by all three compilers?
Clang even allows both qualifier versions simultaneously:
constexpr int foo::N = 3;
const int foo::N = 5;
int main(){
return foo::N; //returns 3
}
what's going on?
Since obviously the value of a variable that has been declared but not defined cannot be used in a constant expression, constexpr pertains only to the definition of a variable. (Of course, if the variable is inline, perhaps because of being a static member declared constexpr, every definition must have constexpr.) It implies const (on the variable itself: constexpr char* is char *const, not const char*), so you haven’t changed the variable’s type. This is no different from
// foo.hpp
extern const int x;
// foo.cpp
constexpr int x=2;
which is perhaps less surprising.
So everything is fine! The variable’s value can be used in constant expressions only in the translation unit that contains the definition, but that’s no surprise, and could easily be construed as a feature for modularity. Clang is buggy to allow two definitions: presumably it’s trying to ignore the (deprecated, as of C++17) out-of-class definition for a constexpr static data member defined in the class.
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.