Visual Studio 2015 Update 3.
I read the Programming. Principles and Practice Using C++ (second edition) by Bjarne Stroustrup. I learn the constexpr functions...
It works:
constexpr int get_value(int n) {
return n + 1;
}
But I can't compile this (instead of the first variant):
constexpr int get_value(int n) {
return ++n;
}
I get the error:
constexpr function return is non-constant
The n is the local variable for the get_value function. I.e. n variable changing doesn't influence to external code.
Why the second variant of the get_value function is wrong?
The second one is not allowed in C++11 constexpr. The standard even had a very similar example (N3337 [dcl.constexpr]/3):
constexpr int prev(int x)
{ return --x; } // error: use of decrement
N3337 [expr.const]/2 explicitly bans "increment or decrement operations" in constant expressions.
C++14 extended constexpr relaxes those requirements, but MSVC doesn't implement that.
The second one is legal under C++14 but it doesn't compile because Visual Studio 2015 has only partial support for constexpr functions. It only has support for single-return constexpr functions and other limitations (like yours), which where in effect in C++11.
See this article (in the constexpr paragraph). Visual Studio "15" will bring improvements to constexpr functions. You'll have to wait a bit :)
Related
I'll lead with the example
#include <array>
// Just in case std::array has superpowers...
template <typename T, unsigned n>
struct dummy {
constexpr unsigned size() const noexcept {
return n;
}
unsigned badsize() const noexcept {
return n;
}
};
void fun()
{
std::array<int, 8> arr{};
static_assert(arr.size() == 8); // OK
dummy<int, 8> arr2{};
static_assert(arr2.size() == 8); // OK
static_assert(arr2.badsize() == 8); // Compiler Error
}
The question is:
What is the language mechanism/rules that has allowed the non-const(expr) variables arr and arr2 to have their non-static but constexpr member functions size() be evaluated as a constant expression (bool-constexpr in particular)?
I've spent some time now searching SO and cppreference.com, but cannot work out why this is allowed.
I've recently had to update similar code to do static_assert(std::tuple_size_v<decltype(arr)> == 8) when upgrading from an older version of GCC, so I thought it was perhaps just some GCC extension at first. But I've now had this kind of code start working again with neweer versions of GCC, and I want to understand what's going on here.
There really isn’t any good reason this is allowed: it’s just that passing the address of the (non-constexpr) local variables as this to a member function is not considered in the rules for constant expressions. It’s even permitted to use this in the function called, but you can’t use any of the (non-static) member variables of the class unless they really were initialized as constants. Of course, these size functions don’t need to do so even if they aren’t actually static.
What’s really confusing is that this permission doesn’t extend to references: using them is considered a read of the effective pointer value, and that must separately be a constant. There are active proposals to allow such usage under the same inevitable restrictions on using the member variables of such an “unknown object”.
Visual C++ is notorious for ignoring constexpr function qualifiers unless absolutely required. Look at the following function:
constexpr int multiply(int l, int r) noexcept
{
return l * r;
}
According to the standard, Visual C++ is completely allowed to not evaluate the rvalue at compile-time:
auto three_times_four = multiply(3, 4);
The workaround I've been using is this ugly force:
constexpr auto constexpr_three_times_four = ;
auto not_constexpr_three_times_four = constexpr_three_times_four;
// use not_constexpr_three_times_four in non-constexpr contexts
// alternatively:
template<auto val>
inline constexpr auto ensure_constexpr = val;
auto not_constexpr_three_times_four = ensure_constexpr<multiply(3, 4)>;
Is there a way I can hint to the compiler that these things should be evaluated at compile-time?
I'm especially annoyed with the following:
namespace l
{
constexpr ::std::uint32_t operator""_crc32(const char * p, ::std::size_t const size) noexcept
{
return crc32(p);
}
}
//...
using namespace l;
search("foo"_crc32);//You don't want to evaluate this at runtime? too bad.
So, what can I do to hint the compiler in this case and avoid these ugly fixes?
There is no mechanism to "hint" to the compiler (any compiler) that a constexpr function "should" be called at compile-time. That's not what constexpr is for. It's not a tool for speeding up execution of code. It's a tool for allowing you to do computations that have to be done at compile-time.
C++20 allows functions to be designated consteval, which ensures that the function must be executed within a constant expression. But even that feature isn't for performance; it's there so that they can add new features of the language (like reflection values) that can only exist at compile time and cannot leak into runtime code.
C++20's constinit allows you to declare non-constant expression variables whose initializer is required to be a constant expression. That's the closest C++ gets to constexpr-as-a-performance-feature.
But otherwise, if the compiler's higher optimization levels aren't calling those functions at compile time, then that's how the compiler has chosen to implement the feature.
I have a simple constexpr class (using c++17)
struct foo {
float x, y;
// ill formed constexpr in vs 2015
foo() {}
constexpr foo(float x, float y) : x(x), y(y) {
}
};
constexpr auto bar() {
return foo(4.0, 5.0);
}
int main() {
auto f = bar();
}
This is illformed bc of the non constexpr default constructor on 2015. But vs 2019 doesnt report a problem.
According to this reference page "all selected ctors" must be constexpr. I assume the word "selected" means "used" and even though default ctor is unused, 2015 wont eval into a constexpr until I make the default ctor constexpr.
Other specs are worded differently but I could not make clear of them either. Also most constexpr examples use the keyword everywhere. An example of selective constexpr use would be nice.
Latest GNU ans Clang behave like vs 2019 but Im not convinced that this was an oversight or bug in vs 2015.
So what is it? Should all ctors be constexpr or is visual studio 2019 correct here?
There has never been a requirement that all constructors of a literal type must be constexpr. The requirement has only been that all functions which get invoked in a constant expression context must be able to be constant expressions (and thus must be declared constexpr).
Note that older versions of Visual Studio did not do a good job of implementing constexpr correctly.
I have the following helper function:
template<typename T, std::size_t N>
constexpr std::size_t Length(const T(&)[N]) {
return N;
}
Which returns the length of a static array. In the past this always has worked but when I do this:
struct Foo
{
unsigned int temp1[3];
void Bar()
{
constexpr std::size_t t = Length(temp1); // Error here
}
};
I get an error when using MSVS 2017:
error C2131: expression did not evaluate to a constant
note: failure was caused by a read of a variable outside its lifetime
note: see usage of 'this'
I was hoping someone can shed light on what I'm doing wrong.
MSVC is correct. Length(temp1) is not a constant expression. From [expr.const]p2
An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:
this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;
temp1 evaluates this implicitly (because you are referring to this->temp1), and so you don't have a constant expression. gcc and clang accept it because they support VLAs as an extension (try compiling with -Werror=vla or -pedantic-errors).
Why isn't this allowed? Well, you could access the underlying elements and potentially modify them. This is completely fine if you are dealing with a constexpr array or an array that is being evaluated as a constant expression, but if you are not, then you cannot possibly have a constant expression as you will be manipulating values that are set at run time.
Length(decltype(temp1){})
seems to work.
Unfortunately, I cannot comment, but Mehrdad 's solution is wrong. The reason: it is
not technically undefined behavior but it is undefined behavior. During constexpr evaluation, the compiler must catch undefined behavior. Therefore, the code is ill-formed.
Your question's already been answered, but in terms of how to "fix" it, a quick-and-dirty way is to replace
Length(temp1)
with
Length(*(true ? NULL : &temp1))
which I think is technically undefined behavior but practically going to work fine for MSVC.
If you need a solution that works despite the UB, you can change Length to use a pointer:
template<typename T, std::size_t N>
constexpr std::size_t Length(const T(*)[N]) {
return N;
}
and then you can use Length(true ? NULL : &temp1).
Is constexpr an indicator for the compiler or does it mandate a behaviour ?
The example at hand is the following :
template<typename T>
std::size_t constexpr getID() { return typeid(T).hash_code(); }
hash_code is a runtime constant, yet this snippet would compile even though a compile time evaluation is requested with constexpr. Only after the return value is used where a compile time constant is expected, would we get noticed that this is not usable as a constexpr function.
So is constexpr a "hint" (much like the inline keyword) or "a binding request" to the compiler ?
Is constexpr a “hint” (like inline) or “a binding request” to the compiler?
It is neither. Forget about when it is evaluated. Everything (with a few minor exceptions, notably involving volatile) is evaluated whenever the compiler deems it necessary to produce the behaviour of the C++ abstract machine. There isn't much else to say about when things are evaluated.
The compiler is free to produce code that evaluates what would be constant expressions at runtime if that doesn't produce a different behaviour. It is free to produce code that evaluates things not marked constexpr at compile-time if it has the smarts.
If not about compile-time vs runtime, what is constexpr about, then?
constexpr allows things to be treated as constant expressions. Anything marked constexpr must have the possibility of producing a constant expression in some way.
In the case of functions, they can be able to produce constant expressions with some arguments but not others. But as long as there is some set of arguments that can result in a constant expression, a function can be marked constexpr. If such a set of arguments is used in a function call, that expression is a constant expression. Does that mean it is evaluated at compile-time? See above. It's evaluated when the compiler deems appropriate. The only thing it means is that you can use it in a context requiring a constant expression.
For variables, either they are constant expressions or not. They have no arguments, so if constexpr they always have to be initialised with constant expressions.
TL;DR: constexpr is about tagging things as being usable in constant expressions, not about deciding when to evaluate them.
With that out of the way, it appears your function template is ill-formed. There is no set of arguments that could result in a constant expression. The standard doesn't require a diagnostic for this, though.
From the C++11 Wiki page:
If a constexpr function or constructor is called with arguments which
aren't constant expressions, the call behaves as if the function were
not constexpr, and the resulting value is not a constant expression.
Likewise, if the expression in the return statement of a constexpr
function does not evaluate to a constant expression for a particular
invocation, the result is not a constant expression.
The constexpr specifier thus expresses the possibility to evaluate something at compile time and is subject to some restrictions when used.
For your particular snippet it seems to me that the C++11 constraint:
exactly one return statement that contains only literal values,
constexpr variables and functions
is not fulfilled, as hash_code is defined to be:
size_t hash_code() const;
In this case the standard draft n3242 says:
For a constexpr function, if no function argument values exist such
that the function invocation substitution would produce a constant
expression (5.19), the program is ill-formed; no diagnostic required.
I believe your example fits here.
constexpr functions can be used to evaluate compile time constants. So it is possible to use it like:
constexpr int func(int a) { return a+2; }
char x[func(10)];
If func is called during runtime, the compiler can evaluate this expression before if possible. But that is not a must but normally done if the input is also const.
It is also important to have constexpr constructors. This is the only chance to get non POD classes constexpr objects.
class Point
{
private:
int x;
int y;
public:
constexpr Point( int _x, int _y) : x(_x), y(_y) {}
constexpr int GetX() const { return x; }
};
constexpr Point p{1,2};
int main()
{
char i[p.GetX()];
return 0;
}
The complete answer to your question has two aspects:
A constexpr function can only be evaluated at compile-time when all
arguments can be evaluated at compile-time. It can still be used as
a normal function which is evaluated at runtime.
An constexpr variable must be initialized with a value evaluated at compile-time.
The compiler has to raise an error if it cannot do this.
You could assign the hash code to a constexpr variable and then get a compiler output:
#include <typeinfo>
#include <array>
template<typename T>
std::size_t constexpr getID() {
return []() {constexpr size_t id = typeid(T).hash_code(); return id;}(); }
int main() {
// both statement generate compiler errors
//std::array<int, typeid(int).hash_code()> a;
//constexpr size_t y = typeid(int).hash_code();
size_t x = getID<int>();
}