I'm having some trouble with constexpr. The book C++ Primer shows a line of code:
constexpr int sz = size(); // only size() is a constexpr function
// this code is right
However the book doesn't give a specific example. So I try the following code by myself:
#include <iostream>
constexpr int fun();
int main()
{
constexpr int f = fun();
std::cout << f << std::endl;
}
constexpr int fun()
{
return 3;
}
But my compiler said fun() is undefined.
If I change constexpr into const, it works well, and if I change my code to define the constexpr function before use:
#include <iostream>
constexpr int fun()
{
return 3;
}
int main()
{
constexpr int f = fun();
std::cout << f << std::endl;
}
It also works well. Can someone tell me why?
A constexpr function does NOT have to be defined before its first use, however the result of any call made prior to definition is not a constant expression.
Source: C++ Standard draft n4296, section 5.20:
A conditional-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;
an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor [ Note: Overload resolution is applied as
usual — end note ];
an invocation of an undefined constexpr function or an undefined constexpr constructor;
...
version from draft 3485 (section 5.19):
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression, but subexpressions of logical AND, logical OR, and conditional operations that are not evaluated are not considered [ Note: An overloaded operator invokes a function. — end note ]:
this [ Note: when evaluating a constant expression, function invocation substitution replaces each occurrence of this in a constexpr member function with a pointer to the class object. — end note ];
an invocation of a function other than a constexpr constructor for a literal class or a constexpr function [ Note: Overload resolution is applied as usual — end note ];
an invocation of an undefined constexpr function or an undefined constexpr constructor
...
The example int x2 = s. t(); in n2235 actually became valid due to the changes made prior to Standardization. However, constexpr int x2 = s. t(); remains an error.
A constant expression function must be defined before its first use. See this paper, end of section 4.1.
Related
Lambda's operator() is implicitly constexpr according to https://en.cppreference.com/w/cpp/language/lambda
When this specifier (constexpr) is not present, the function call operator or any given operator template specialization will be constexpr anyway, if it happens to satisfy all constexpr function requirements
And a requirement of a constexpr-function according to https://en.cppreference.com/w/cpp/language/constexpr
there exists at least one set of argument values such that an invocation of the function could be an evaluated subexpression of a core constant expression (for constructors, use in a constant initializer is sufficient) (since C++14). No diagnostic is required for a violation of this bullet.
In the next example, the function t() always throws an exception by calling lambda l():
auto l = []()->bool { throw 42; };
constexpr bool t() { return l(); }
GCC rejects this function with the error:
call to non-'constexpr' function '<lambda()>'
but Clang accepts the program (until the function t() is used in a constant evaluation), meaning that it considers l() a constexpr-function, demo: https://gcc.godbolt.org/z/j1z7ee3Wv
Is it a bug in Clang, or such compiler behavior is also acceptable?
All three compilers do issue an error when you actually try to use the result of t() in a context that requires a constant expression. For example:
auto l = []()->bool { throw 42; };
constexpr bool t() { return l(); }
template <bool x>
struct dummy {};
int main() {
dummy< t() > d; // error: t() is not a constant expression
}
As mentioned in a comment by NathanOliver, your quote already states:
[...] No diagnostic is required for a violation of this bullet.
Compilers need not necessarily proove that there is no set of argument values that allow the function to return a constant expression. On the other hand, a compiler can easily verify for a given argument value, that the result is not a constant expression.
The following code fails to compile:
// template<class>
struct S {
int g() const {
return 0;
}
constexpr int f() const {
return g();
}
};
int main()
{
S /*<int>*/ s;
auto z = s.f();
}
GCC, for example, complains: error: call to non-constexpr function ‘int S::g() const’. This is perfectly reasonable. But if I turn S into a template, the code compiles (checked with MSVC 15.3, GCC 7.1.0, clang 4.0.1).
Why? Does constexpr has any special meaning in class templates?
As far as I understand it, this code is incorrect, but the standard does not require that compilers produce an error (why?).
Per [dcl.constexpr]
The definition of a constexpr function shall satisfy the following constraints:
...every constructor call and implicit conversion used in initializing the return value (6.6.3, 8.5) shall be
one of those allowed in a constant expression
A call to g() is not allowed in a constant expression. Per [expr.const]:
A conditional-expression is a core constant expression unless it involves one of the following as a potentially
evaluated subexpression...:
— an invocation of a function other than [...] a constexpr function
It looks like some compilers may allow you to do what you're doing because z isn't declared constexpr so the value doesn't need to be known at compile-time. If you change your code to
constexpr auto z = s.f();
you'll note that all those compilers will proceed to barf, template or not.
Please consider the following two C++14 programs:
Program 1:
struct S { constexpr int f() const { return 42; } };
S s;
int main() { constexpr int x = s.f(); return x; }
Program 2:
struct S { constexpr int f() const { return 42; } };
int g(S s) { constexpr int x = s.f(); return x; }
int main() { S s; return g(s); }
Are neither, either or both of these programs ill-formed?
Why/why not?
Both programs are well-formed. The C++14 standard requires that s.f() be a constant expression because it is being used to initialize a constexpr variable, and in fact it is a core constant expression because there's no reason for it not to be. The reasons that an expression might not be a core constant expression are listed in section 5.19 p2. In particular, it states that the evaluation of the expression would have to do one of several things, none of which are done in your examples.
This may be surprising since, in some contexts, passing a non-constant expression to a constexpr function can cause the result to be a non-constant expression even if the argument isn't used. For example:
constexpr int f(int) { return 42; }
int main()
{
int x = 5;
constexpr auto y = f(x); // ill-formed
}
However, the reason this is ill-formed is because of the lvalue-to-rvalue conversion of a non-constant expression, which is one of the things that the evaluation of the expression is not allowed to do. An lvalue-to-rvalue conversion doesn't occur in the case of calling s.f().
I can't seem to find a compelling passage or example in the standard that directly addresses the issue of calling a constexpr member function on a non-constexpr instance, but here are some that may be of help (from draft N4140):
[C++14: 7.1.5/5]:
For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting
constexpr constructor, if no argument values exist such that an invocation of the function or constructor
could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no
diagnostic required.
constexpr int f(bool b)
{ return b ? throw 0 : 0; } // OK
constexpr int f() { return f(true); } // ill-formed, no diagnostic required
From this I take that the program is not outright ill-formed just because a constexpr function has a possible non-constexpr path.
[C++14: 5.19]:
int x; // not constant
struct A {
constexpr A(bool b) : m(b?42:x) { }
int m;
};
constexpr int v = A(true).m; // OK: constructor call initializes
// m with the value 42
constexpr int w = A(false).m; // error: initializer for m is
// x, which is non-constant
This is somewhat closer to your example programs, here a constexpr constructor may reference a non-constexpr variable depending on the value of the argument, but there is no error if this path is not actually taken.
So I don't think either program you presented should be ill-formed, but I cannot offer convincing proof :)
This sounds like a quiz question, and not presented by a student, but the professor testing the public on stackoverflow, but let's see...
Let's start with the One Definition Rule. It's clear neither version violates that, so they both pass that part.
Then, to syntax. Neither have syntax failures, they'll both compile without issue if you don't mind the potential blend of a syntax and semantic issue.
First, the simpler semantic issue. This isn't a syntax problem, but f(), in both versions, is the member of a struct, and the function clearly makes no change to the owning struct, it's returning a constant. Although the function is declared constexpr, it is not declared as const, which means if there were some reason to call this as a runtime function, it would generate an error if that attempt were made on a const S. That affects both versions.
Now, the potentially ambiguous return g(S()); Clearly the outer g is a function call, but S may not be so clear as it would be if written return g(S{}); With {} initializing S, there would be no ambiguity in the future should struct S be expanded with an operator() (the struct nearly resembles a functor already). The constructor invoked is automatically generated now, and there is no operator() to create confusion for the compiler at this version, but modern C++14 is supposed to offer clearer alternatives to avoid the "Most Vexing Parse", which g(S()) resembles.
So, I'd have to say that based on semantic rules, they both fail (not so badly though).
I'm trying to static instantiate some objects at compile time. What I need is to set to a member int variable an incremented value. For example, the first object I create will have the 0 value, the second 1, the third 2...
Summarizing I need something like this but it has to work as constexpr.
//header
class MyClass final {
private:
static int IDcount;
public:
const int ID;
constexpr MyClass(args);
//~MyClass();
};
//source
int MyClass::IDcount = 0;
constexpr MyClass::MyClass(args) : ID(MyClass::IDcount++) {
}
Is there a way to achieve this at compile time (without taking the ID as argument of the constructor)
It can't be done the way you've defined it, but there is a non-standard but widely implemented preprocessor trick that could be employed.
#include <iostream>
struct MyClass final {
constexpr MyClass(int myid, const char *myname)
: id(myid), name(myname) {}
int id;
const char *name;
};
constexpr MyClass m[]{
MyClass(__COUNTER__, "Larry"),
MyClass(__COUNTER__, "Moe"),
MyClass(__COUNTER__, "Curly")
};
int main()
{
for (auto const &obj : m)
std::cout << obj.id << '\t' << obj.name << "\n";
}
The __COUNTER__ macro is defined in Microsoft's Visual C++, gcc since version 4.3 and clang.
When run, this program produces:
0 Larry
1 Moe
2 Curly
A constexpr-function or ctor must be a valid core constant expression on at least one path:
7.1.5 The constexpr specifier [dcl.constexpr]
5 For a non-template, non-defaulted constexpr function or a non-template, non-defaulted, non-inheriting constexpr constructor, if no argument values exist such that an invocation of the function or constructor could be an evaluated subexpression of a core constant expression (5.19), the program is ill-formed; no diagnostic required.
Which means it cannot modify a global object on all paths:
5.19 Constant expressions [expr.const]
A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:
modification of an object (5.17, 5.2.6, 5.3.2) unless it is applied to a non-volatile lvalue of literal type
that refers to a non-volatile object whose lifetime began within the evaluation of e;
I found this piece of code doesn't work:
typedef int (*fp)(int a, int b);
constexpr fp addition()
{
return [](int a, int b){ return a+b; };
}
#include <iostream>
int main()
{
fp fun = addition();
std::cout << fun(2,2);
}
It gives me error
cexpr.cpp: In function 'constexpr int (* addition())(int, int)':
cexpr.cpp:5:43: error: call to non-constexpr function 'addition()::<lambda(int,
int)>::operator int (*)(int, int)() const'
Why is that? I'm not calling it here.
Direct approach works:
typedef int (*fp)(int a, int b);
#include <iostream>
int main()
{
fp fun = [](int a, int b){ return a+b; };
std::cout << fun(2,2);
}
I'm using MinGW with g++ version 4.7.2.
Your function fp() does not return a literal type, therefore it cannot be a constexpr function:
From 7.1.5: "The definition of a constexpr function shall satisfy the following constraints:
it shall not be virtual (10.3);
its return type shall be a literal type;
each of its parameter types shall be a literal type;
its function-body shall be = delete, = default, or a compound-statement that contains only
null statements,
static_assert-declarations
typedef declarations and alias-declarations that do not define classes or enumerations,
using-declarations,
using-directives,
and exactly one return statement;"
I do not think there is any bug here, and especially nothing related to lambdas as mentioned in an earlier answer: variables simply cannot be declared inside of a constexpr function.
According to N3376 working draft of the standard section 5.19 [expr.const]:
Certain contexts require expressions that satisfy additional
requirements as detailed in this sub-clause; other contexts have
different semantics depending on whether or not an expression satisfies
these requirements. Expressions that satisfy these requirements are
called constant expressions. [ Note: Constant expressions can be
evaluated during translation.— end note ]
It goes on to say:
A conditional-expression is a core constant expression unless it
involves one of the following as a potentially evaluated subexpression
(3.2), but subexpressions of logical AND (5.14), logical OR (5.15),
and conditional (5.16) operations that are not evaluated are not
considered [ Note: An overloaded operator invokes a function.— end
note ]:
Which lists under it:
— a lambda-expression (5.1.2);
So while I don't know enough standardese, I believe this says that a constexpr shouldn't have a lambda expression inside.
The error message gcc gave you was precise and correct:
error: call to non-constexpr function 'addition()::
<lambda(int,int)>::
operator int (*)(int, int)() const'
I've reformatted it a bit and added emphasis. By coercing the lambda to a function pointer, you're implicitly calling the automatically-created conversion function from lambda to pointer to function of type "auto (int, int)->int", which is not a constexpr function because the automatically-created conversion function is not declared constexpr (and the standard doesn't require it to be).