The follwing code doesn't compile with g++/clang++.
constexpr int bar(int v) {
if (v > 0){
return v * 2;
}
return 2;
}
constexpr int foo(const int v) {
constexpr auto x = bar(v); // error
return v;
}
int main() {
constexpr auto a = foo(1);
constexpr auto b = bar(1); // ok
}
The error message is: x must be initailized by a constant expression
But from the line (ok) you see that bar() is constexpr.
if I change the body of foo() to
constexpr int foo(const int v) {
return bar(v);
}
its ok!
I don't get this clear, why the first form isn't possilble.
I used g++-6.2.1, g++-7.0.0 and clang++-3.9.0
The fix is this
constexpr int foo(const int v) {
auto x = bar(v);
return v;
}
The keyword constexpr means two very slightly different things. A constexpr variable must be evaluated at compile time, whereas a constexpr function must be possible to evaluate at compile time. There is nothing to prevent you from calling foo at runtime. This means...
The argument v is not necessarily constexpr.
When bar is called with b the answer might not be constexpr.
The result of cannot be stored in a constexpr variable as it might not be constexpr.
If foo is called at compile time then x is not stored, it is a temporary variable within the compiler, so making it constexpr doesn't make any sense.
The constexpr'ness of x can only make sense if foo is evaluated at runtime, in which case it cannot be constexpr, which cases an error.
Related
I always assumed:
writing to const_cast ed variable is UB
there is no UB allowed in constexpr
So I am confused why this code compiles:
constexpr int fn(){
int v = 42;
return [v]() {
const_cast<int&>(v)+=5;
return v;
}();
}
static constexpr auto val = fn();
int main() {
return val;
}
note: I know there is no reason to not allow this to work since it is obvious what the result should be, I am more interested in the legal explanation why is this allowed.
This part is true:
there is no UB allowed in constexpr
This part is not:
writing to const_cast-ed variable is UB
The actual rule is, from [dcl.type.cv]/4:
Any attempt to modify ([expr.ass], [expr.post.incr], [expr.pre.incr]) a const object ([basic.type.qualifier]) during its lifetime ([basic.life]) results in undefined behavior.
Note that the relevant part is whether the object is const or not - not whether any of the path that you took to get to it is const. And in this case, v is not a const object and nor is the one created in the lambda when you're copying it.
However, if you declare v to be const, then the one declared in the lambda would also be declared const, and thus the attempt to modify it would be undefined behavior. As a result, your code will no longer compile.
The lambda expression translates to something similar to this:
struct unnamed {
int v;
int operator()() const {
const_cast<int&>(v)+=5;
return v;
}
};
Without the const_cast you cannot modify v inside the operator() because the operator is a const method, but v itself is not const.
Same situation as with
struct foo {
int x = 0;
void operator() const {
const_cast<int&>(x) += 42;
}
};
Then this is "ok":
foo f;
f();
While this is undefined:
const foo f;
f();
I have read the std::is_constant_evaluated() definition, but I still not sure why (1) is not working with the latest GCC: error: 'x' is not a constant expression
template<auto v>
struct s
{};
constexpr void f(int x)
{
if (std::is_constant_evaluated())
{
// constexpr int z=x; (1)
// s<x> a; (2)
}
}
int main(int argc, char* argv[])
{
f(4);
//f(argc);
return 0;
}
By the standard, should that work?
Or just the GCC implementation is buggy?
Somehow can I achieve the expected behavior? Which is basically:
With branching on std::is_constant_evaluated()
if it is true: the code can use variables as constexpr (like (2))
if it is false: the code use variables as non-constexpr
UPDATE
Can I 'transport' the constexpr-essiveness information into a function? Basically to decide in f() that it was call with constexpr x or not.
UPDATE
A more complex example about what I would like to achieve: this sample should stringify the parameter in compile time if possible.
template<auto v>
struct dummy_stringify
{
static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};
constexpr void f(int x)
{
if (std::is_constant_evaluated())
{
std::puts("A compile time calculation:");
//std::puts(dummy_stringify<x>::str);
} else
{
std::cout<<"A runtime calculation:"<<std::endl;
std::cout<<x<<std::endl;
}
}
int main(int argc, char* argv[])
{
f(4);
f(argc);
return 0;
}
x is not a constant expression, no matter how f itself is evaluated. That's a regular if right there (how is_constant_evaluated is meant to be used). It's not a discarded branch, so it has to contain well-formed code even when f is not constant evaluated. When x won't be a constant expression the function will still contain that (unexecuted) branch, and it will attempt to use x where a constant expression is required. That's plain ill-formed.
GCC is very much correct not to accept it.
The fundamental issue here is that, even with a constexpr (or even consteval) function being called during constant evaluation (and under an is_constant_evaluated check), there is still only one function shared among all argument values. You therefore can’t ever use a function parameter as a constant expression (even if the call with that parameter is a constant expression). If you want a constant-expression parameter, it has to be a template parameter.
UPDATE
I have found a solution with a little helper class (of course one can use std::integral_constant)
template<auto val_>
struct val
{
static constexpr auto value=val_;
};
template<auto v>
struct dummy_stringify
{
static constexpr auto str=v==4 ? "4" : "31"; // this is just an example; imagine here a much more complex logic
};
#include <iostream>
using namespace std;
template<class T>
constexpr void f(T x)
{
if constexpr(requires{ T::value; })
{
std::puts("A compile time calculation:");
std::puts(dummy_stringify<T::value>::str);
} else
{
std::cout<<"A runtime calculation:"<<std::endl;
std::cout<<x<<std::endl;
}
}
int main(int argc, char* argv[])
{
f(val<4>{});
f(argc);
return 0;
}
It can be improved with a template<char...> auto operator""_v(); to f(4_v)
This question already has answers here:
What is the use of a constexpr on a non-const member function?
(2 answers)
Closed 4 years ago.
I cannot understand the purpose of marking the setter function as constexpr, that is allowed since C++14.
My misunderstanding comes from the next situation:
I declare a class with a constexpr c-tor, and I am about to use it in a constexpr context, by creating a constexpr instance of that class constexpr Point p1. An object p1 now is constant and its value could not be changed, so the constexpr setter could not be called.
On the other hand, when I create an instance of my class Point in a non-constexpr context Point p, I can call the setter for that object, but now setter will not execute at compile-time, because the object is not constexpr!
As a result, I do not understand how can I enhance the performance of my code using constexpr for setters.
This is the code that demonstrates calling a constexpr setter on an non-constexpr object, that means run-time computation, instead of the compile-time:
class Point {
public:
constexpr Point(int a, int b)
: x(a), y(b) {}
constexpr int getX() const noexcept { return x; }
constexpr int getY() const noexcept { return y; }
constexpr void setX(int newX) noexcept { x = newX; }
constexpr void setY(int newY) noexcept { y = newY; }
private:
int x;
int y;
};
int main() {
Point p{4, 2};
constexpr Point p1{4, 2};
p.setX(2);
}
Could anyone help me to understand what is the purpose of marking the setter function as constexpr?
Basically it is nice when you have to deal with constexpr function.
struct Object {
constexpr void set(int n);
int m_n = 0;
};
constexpr Object function() {
Object a;
a.set(5);
return a;
}
constexpr Object a = function();
The idea is to be able to perform compile time initialization within another functions that will be executed at the compile time. It is not done to be applied on constexpr object.
Another things to know is that constexpr member functions are not const member functions since C++14 :).
The need arise with new constexpr rule with C++14: inside constexpr function, you can now use multiple statements, including for loops and control flow.
Here's an example:
constexpr int count5(int start) {
int acc = 0;
for (int i = start ; i<start+5 ; ++i) {
acc += i;
}
return acc;
}
constexpr int value = count5(10); // value is 60!
As you can see, we can do many mutation to variable in a constexpr context. The compiler becomes like an interpreter, and as long as the result of the constexpr fonction is consistent and you don't mutate already computed constexpr variables, it may mutate the values during the interpretation.
A function with constexpr qualifier will evaluate the return of the function at compile time, which can significantly boost performance of a program (no extra computation, no instruction counter jumping, etc.). There are a few requirements to qualify a function thusly, so check out this explanation from IBM.
struct Foo
{
constexpr static int n = 10;
};
void f(const int &x) {}
int main()
{
Foo foo;
f(Foo::n);
return 0;
}
I get error: main.cpp|11|undefined reference to `Foo::n'|. Why?
The compiler error is required by the standard. Since your function
void f(const int& x)
takes it argument by reference, in the call
f(Foo::n);
the variable Foo::n is odr-used. Hence a definition is required.
There are 2 solutions.
1 Define Foo::n:
struct Foo
{
constexpr static int n = 10; // only a declaration
};
constexpr int Foo::n; // definition
2 Take the argument of f by value:
void f(int x);
What compiler version do you use? It seems, it has some issues with C++11 dialect (ideone.com compiled that with 100% success).
Maybe, it's a good idea to try this instead?
struct Foo
{
static int n;
};
int Foo::n = 10;
This question already has answers here:
How to ensure constexpr function never called at runtime?
(5 answers)
Closed 1 year ago.
In C++11 we get constexpr:
constexpr int foo (int x) {
return x + 1;
}
Is it possible to make invocations of foo with a dynamic value of x a compile time error? That is, I want to create a foo such that one can only pass in constexpr arguments.
Replace it with a metafunction:
template <int x> struct foo { static constexpr int value = x + 1; };
Usage:
foo<12>::value
Unfortunately, there is no way guarantee that a constexpr function, even the most trivial one, will be evaluated by the compiler unless absolutely necessary. That is, unless it appears in a place where its value is required at compile time, e.g. in a template. In order to enforce the compiler to do the evaluation during compilation, you can do the following:
constexpr int foo_implementation (int x) {
return x + 1;
}
#define foo(x) std::integral_constant<int, foo_implementation(x)>::value
and then use foo in your code as usual
int f = foo(123);
The nice thing about this approach is that it guarantees compile-time evaluation, and you'll get a compilation error if you pass a run-time variable to foo:
int a = 2;
int f = foo(a); /* Error: invalid template argument for 'std::integral_constant',
expected compile-time constant expression */
The not so nice thing is that it requires a macro, but this seems currently inevitable if you want both guaranteed compile-time evaluation and pretty code. (I'd love to be proven wrong though!)
Yes, it can now be done in purely idiomatic C++, since C++20 added support for this kind of problem. You annotate a function with consteval and can be sure that it's being evaluated during compile time. https://en.cppreference.com/w/cpp/language/consteval
consteval int foo( int x ) {
return x + 1;
}
int main( int argc, char *argv[] )
{
return foo( argc ); // This will not compile
return foo( 1 ); // This works
}
Also see this godbolt.org demo in the 3 most relevant compilers.
I would use static_assert as shown in this example
#include<iostream>
constexpr int foo(int x) {
return x+1;
}
int main() {
// Works since its static
std::cout << foo(2) << std::endl;
static_assert(foo(2) || foo(2) == 0, "Not Static");
// Throws an compile error
int in = 3;
std::cout << foo(in) << std::endl;
static_assert(foo(in) || foo(in) == 0, "Not Static");
}
For more infos: http://en.cppreference.com/w/cpp/language/static_assert