#include <utility>
struct A {
constexpr auto one(int a) {
return std::integral_constant<int, _data[a]>{};
}
constexpr int two(int a) const {
return _data[a];
}
int _data[10];
};
int main() {
constexpr auto ex = A{{1,2,3,4,5,6,7,8,9,10}};
std::integral_constant<int, ex.two(3)> b{};
}
The code above will not compile in trunk Clang. The error is in the one() member function, and says:
cc.cpp:57:44: note: implicit use of 'this' pointer is only allowed
within the evaluation of a call to a 'constexpr' member function.
Obviously, the function is marked constexpr, and if you comment out the one() member, everything compiles fine, so we are clearly able to create the integral_constant from the ex, but not directly from the struct? It seems like, when I need the auto return type deduction, it fails and claims the function is not constexpr?
Is this expected? I feel like it should not be a problem, and I would be surprised if this was expected behavior.
If you consider this statement in [dcl.constexpr]/7:
A call to a constexpr function produces the same result as a call to an equivalent non-constexpr function in all respects except that a call to a constexpr function can appear in a constant expression.
Consider the non-constexpr equivalent function A::one(). _data[a] cannot be used in a constant expression (as a non-type template argument) because it would involve the evaluation of this, from [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:
(2.1) — this (5.1.1), except in a constexpr function or a constexpr constructor that is being evaluated as
part of e;
Since the non-constexpr equivalent is ill-formed, it is reasonable that the constexpr function give the same result.
Ont the other hand, two() is a well-formed member function regardless of constexpr and your use of ex.two(3) is valid as a constant expression - that's why it compiles.
constexpr functions are made so that they can be called both at compile-time and run-time.
Code with a constexpr function is well-formed if you can omit constexpr and get a proper plain function. In other words it must compile as a run-time function.
If the body of constexpr function cannot be calculated at compile-time, it's still compiled, but you cannot use it in a compile-time context such as template arguments.
If constexpr method is called on constexpr object, this is considered constexpr.
In case of one it is ill-formed, because when it's compiled to be run at run-time, _data[a] is considered to be a run-time expression, because a is not a constant expression, even though this and this->_data are.
In case of two it compiles fine, because it works fine at runtime, and at compile-time this is constexpr as much as a, so that this->_data[a] is constexpr and everything works fine.
Related
I understand that a strongly typed enumerator can be converted to its underlying type as:
template<typename E> constexpr
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename std::underlying_type<E>::type>(e);
}
However, this is working in run-time.
Since enumerators are there already in compilation time, is there a way to do such conversion during compilation time?
As herb sutter mentioned in the below link,
When does a constexpr function get evaluated at compile time?
constexpr functions will be evaluated at compile time when all its arguments are constant expressions and the result is used in a constant expression as well. A constant expression could be a literal (like 42), a non-type template argument (like N in template class array;), an enum element declaration (like Blue in enum Color { Red, Blue, Green };, another variable declared constexpr, and so on.
They might be evaluated when all its arguments are constant expressions and the result is not used in a constant expression, but that is up to the implementation.
The function you wrote is OK to be used at compile time.
template<typename E> constexpr
auto to_integral(E e) -> typename std::underlying_type<E>::type
{
return static_cast<typename> std::underlying_type<E>::type>(e);
}
enum class A : int { a };
static_assert(to_integral(A::a) == 0);
This should compile, indicating that the function can be ran at compile time.
However, constexpr functions only indicate that the function complies with all requirements to be executed at compile time. To enforce this being calculated (even at -O0), you need to make your variables also constexpr.
constexpr auto i = to_integral(A::a);
i = 42;
For a variable, the constexpr simply means: initialize at compile time. Afterwards, you can use it as if it was runtime.
In the example above, I'm convinced that most compilers will optimize the code regardless of the constexpr keyword. (Given -O2 or -O3) However if the code becomes more complex the constexpr is required to force them to optimize it, regardless of the cost.
Is it possible to produce a compile-time boolean value based on whether or not a C++11 expression is a constant expression (i.e. constexpr) in C++11? A few questions on SO relate to this, but I don't see a straight answer anywhere.
I once wrote it (EDIT: see below for limitations and explanations). From https://stackoverflow.com/a/10287598/34509 :
template<typename T>
constexpr typename remove_reference<T>::type makeprval(T && t) {
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
However there are many kinds of constant expressions. The above answer detects prvalue constant expressions.
Explanation
The noexcept(e) expression gives false iff e contains
a potentially evaluated call to a function that does not have a non-throwing exception-specification unless the call is a constant expression,
a potentially evaluated throw expression,
a potentially evaluated throwable form of dynamic_cast or typeid.
Note that the function template makeprval is not declared noexcept, so the call needs to be a constant expression for the first bullet not to apply, and this is what we abuse. We need the other bullets to not apply aswell, but thanksfully, both a throw and a throwable dynamic_cast or typeid aren't allowed in constant expressions aswell, so this is fine.
Limitations
Unfortunately there is a subtle limitation, which may or may not matter for you. The notion of "potentially evaluated" is much more conservative than the limits of what constant expressions apply. So the above noexcept may give false negatives. It will report that some expressions aren't prvalue constant expressions, even though they are. Example:
constexpr int a = (0 ? throw "fooled!" : 42);
constexpr bool atest = isprvalconstexpr((0 ? throw "fooled!" : 42));
In the above atest is false, even though the initialization of a succeeded. That is because for being a constant expression, it suffices that the "evil" non-constant sub-expressions are "never evaluated", even though those evil sub-expressions are potentially-evaluated, formally.
As of 2017, is_constexpr is not possible in C++11. That sounds like an odd thing to say, so let me explain a bit of the history.
First, we added this feature to resolve a defect: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1129
Johannes Schaub - litb posted a constexpr detection macro that relied on the provision that constant expressions are implicitly noexcept. This worked in C++11, but was never implemented by at least some compilers (for instance, clang). Then, as part of C++17, we evaluated Removing Deprecated Exception Specifications from C++17. As a side-effect of that wording, we accidentally removed that provision. When the Core Working Group discussed adding the provision back in, they realized that there were some serious problems with doing so. You can see the full details in the LLVM bug report. So rather than adding it back in, we decided to consider it a defect against all versions of standard and retroactively removed it.
The effect of this is that there is, to my knowledge, no way to detect whether an expression is usable as a constant expression.
Yes, this is possible. One way to do it (which is valid even with the recent noexcept changes) is to take advantage of the C++11 narrowing conversion rules:
A narrowing conversion is an implicit conversion [...] from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.
(emphasis mine). List initialization generally disallows narrowing conversions, and when combined with SFINAE we can build gadgets for detecting whether an arbitrary expression is a constant expression:
// p() here could be anything
template<int (*p)()> std::true_type is_constexpr_impl(decltype(int{(p(), 0U)}));
template<int (*p)()> std::false_type is_constexpr_impl(...);
template<int (*p)()> using is_constexpr = decltype(is_constexpr_impl<p>(0));
constexpr int f() { return 0; }
int g() { return 0; }
static_assert(is_constexpr<f>());
static_assert(!is_constexpr<g>());
Live demonstration.
The key here is that int{(expr, 0U)} contains a narrowing conversion from unsigned int to int (and thus is ill-formed), unless expr is a constant expression, in which case the entire expression (expr, 0U) is a constant expression whose evaluated value fits into the type int.
The following is an implementation of is_constexpr for functions, not for arbitrary expressions, for C++11 and C++17. It requires the arguments to the function you want to test to be default constructible, though.
#include <type_traits>
struct A {}; // don't make it too easy, use a UDT
A f1(A a) { return a; } // is_constexpr -> false
constexpr A f2(A a) { return a; } // is_constexpr -> true
// The following turns anything (in our case a value of A) into an int.
// This is necessary because non-type template arguments must be integral
// (likely to change with C++20).
template <class T> constexpr int make_int(T &&) { return 0; }
// Helper to turn some function type (e.g. int(float)) into a function
// pointer type (e.g. int (*)(float)).
template <class T> struct signature_from;
template <class R, class... Args> struct signature_from<R(Args...)> {
using type = R(*)(Args...);
};
// See std::void_t for the idea. This does it for ints instead of types.
template <int...> using void_from_int = void;
// The fallback case: F is not a function pointer to a constexpr function
template <class T, typename signature_from<T>::type F, class = void_from_int<>>
struct is_constexpr {
static constexpr bool value = false;
};
// If void_from_int<make_int(F(Args()...))> doesn't lead to a substitution
// failure, then this is the preferred specialization. In that case F must
// be a function pointer to a constexpr function. If it is not, it could
// not be used in a template argument.
template <class R, class... Args, typename signature_from<R(Args...)>::type F>
struct is_constexpr<R(Args...), F, void_from_int<make_int(F(Args()...))>>
{
static constexpr bool value = true;
};
// proof that it works:
static_assert(!is_constexpr<A(A), f1>::value, "");
static_assert( is_constexpr<A(A), f2>::value, "");
#if __cplusplus >= 201703
// with C++17 the type of the function can be deduced:
template<auto F> struct is_constexpr2 : is_constexpr<std::remove_pointer_t<decltype(F)>, F> {};
static_assert(!is_constexpr2<f1>::value, "");
static_assert( is_constexpr2<f2>::value, "");
#endif
See it in action at https://godbolt.org/g/rdeQme.
C++20 added std::is_constant_evaluated()
This allows checking if a certain expression is a constant evaluated expression, i.e. being evaluated at compile time.
Usage example:
constexpr int foo(int num) {
// below is true in case the condition is being evaluated at compile time
// side note, using: if constexpr (std::is_constant_evaluated())
// would be evaluated always to true, so you should use a simple if!
if (std::is_constant_evaluated()) {
return foo_compiletime(num);
}
else {
return foo_runtime(num);
}
}
int main() {
constexpr auto t1 = foo(6); // reaches foo_compiletime
const auto t2 = foo(6); // reaches foo_compiletime
int n = rand() % 10;
const auto t3 = foo(n); // reaches foo_runtime
auto t4 = foo(6); // unfortunately, reaches foo_runtime
}
The last call in the example above would reach foo_runtime, since the call is not within a constant expression context (the result is not being used as a constant expression, see also this SO answer).
This may lead to undesired pessimization, compared to the case of leaving the decision to the user, who may call:
auto t4 = foo_compiletime(6);
And the compiler is allowed to perform the operations inside foo_compiletime at compile time, if it is declared as constexpr function, or would be obliged to do that if it is declared consteval. However, once we leave the decision to the compiler, we will reach foo_runtime, unless we explicitly direct the compiler to go for foo_compiletime, by taking the result into a const, constexpr or constinit variable. Which then, in a way, omits the value of having one function for both scenarios, if the user is required to help the compiler peek the right path.
Another possible option for the call to be optimized, is:
constexpr auto temp = foo(6); // foo_compiletime
auto t4 = temp;
But again, we require the user to be aware of the inner behavior of foo, which is not exactly what we want to achieve.
See the pessimization in this code.
See more on that in this great blog post on the subject.
In the following piece of C++11 code, the function get is constexpr
but it tries to construct an instance via the non-constexpr constructor.
template <typename T>
struct S
{
S() {}
static constexpr S get() { return S(); }
};
int main()
{
// S<int> s1;
// auto s2 = s1.get();
}
While this code compiles with GCC, it fails with the compiler we use at
work with the message
constexpr function return is non-constant.
We started a discussion whether the compiler is allowed to issue an error in
this case. I think that the compiler has to accept the code. Otherwise I do
not see how std::time_point could work in C++11 because its constructor is
constexpr only since C++14.
So is this a quality-of-implementation thing or does the standard say
something about uninstantiated templates w.r.t constexpr?
Further, would it change anything if the code in the comments were
activated (i.e. invoking a constexpr function on a non-constexpr
object)?
This line is fine:
S<int> s1;
but the following definition of get is ill-formed:
static constexpr S get() { return S(); }
since it does not return a literal type since S does not have a constexpr constructor.
From the draft C++11 standard section 7.1.5 The constexpr specifier [dcl.constexpr]:
The definition of a constexpr function shall satisfy the following constraints:
its return type shall be a literal type;
and later on the section it says (emphasis mine):
If the instantiated template specialization of a constexpr function
template or member function of a class template would fail to satisfy
the requirements for a constexpr function or constexpr constructor,
that specialization is not a constexpr function or constexpr
constructor. [ Note: If the function is a member function it will
still be const as described below. —end note ] If no specialization
of the template would yield a constexpr function or constexpr
constructor, the program is ill-formed; no diagnostic required.
Note in the non-template case both gcc and clang generate an error since the return type is not a literal see it live.
Is it possible to produce a compile-time boolean value based on whether or not a C++11 expression is a constant expression (i.e. constexpr) in C++11? A few questions on SO relate to this, but I don't see a straight answer anywhere.
I once wrote it (EDIT: see below for limitations and explanations). From https://stackoverflow.com/a/10287598/34509 :
template<typename T>
constexpr typename remove_reference<T>::type makeprval(T && t) {
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
However there are many kinds of constant expressions. The above answer detects prvalue constant expressions.
Explanation
The noexcept(e) expression gives false iff e contains
a potentially evaluated call to a function that does not have a non-throwing exception-specification unless the call is a constant expression,
a potentially evaluated throw expression,
a potentially evaluated throwable form of dynamic_cast or typeid.
Note that the function template makeprval is not declared noexcept, so the call needs to be a constant expression for the first bullet not to apply, and this is what we abuse. We need the other bullets to not apply aswell, but thanksfully, both a throw and a throwable dynamic_cast or typeid aren't allowed in constant expressions aswell, so this is fine.
Limitations
Unfortunately there is a subtle limitation, which may or may not matter for you. The notion of "potentially evaluated" is much more conservative than the limits of what constant expressions apply. So the above noexcept may give false negatives. It will report that some expressions aren't prvalue constant expressions, even though they are. Example:
constexpr int a = (0 ? throw "fooled!" : 42);
constexpr bool atest = isprvalconstexpr((0 ? throw "fooled!" : 42));
In the above atest is false, even though the initialization of a succeeded. That is because for being a constant expression, it suffices that the "evil" non-constant sub-expressions are "never evaluated", even though those evil sub-expressions are potentially-evaluated, formally.
As of 2017, is_constexpr is not possible in C++11. That sounds like an odd thing to say, so let me explain a bit of the history.
First, we added this feature to resolve a defect: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1129
Johannes Schaub - litb posted a constexpr detection macro that relied on the provision that constant expressions are implicitly noexcept. This worked in C++11, but was never implemented by at least some compilers (for instance, clang). Then, as part of C++17, we evaluated Removing Deprecated Exception Specifications from C++17. As a side-effect of that wording, we accidentally removed that provision. When the Core Working Group discussed adding the provision back in, they realized that there were some serious problems with doing so. You can see the full details in the LLVM bug report. So rather than adding it back in, we decided to consider it a defect against all versions of standard and retroactively removed it.
The effect of this is that there is, to my knowledge, no way to detect whether an expression is usable as a constant expression.
Yes, this is possible. One way to do it (which is valid even with the recent noexcept changes) is to take advantage of the C++11 narrowing conversion rules:
A narrowing conversion is an implicit conversion [...] from an integer type or unscoped enumeration type to an integer type that cannot represent all the values of the original type, except where the source is a constant expression whose value after integral promotions will fit into the target type.
(emphasis mine). List initialization generally disallows narrowing conversions, and when combined with SFINAE we can build gadgets for detecting whether an arbitrary expression is a constant expression:
// p() here could be anything
template<int (*p)()> std::true_type is_constexpr_impl(decltype(int{(p(), 0U)}));
template<int (*p)()> std::false_type is_constexpr_impl(...);
template<int (*p)()> using is_constexpr = decltype(is_constexpr_impl<p>(0));
constexpr int f() { return 0; }
int g() { return 0; }
static_assert(is_constexpr<f>());
static_assert(!is_constexpr<g>());
Live demonstration.
The key here is that int{(expr, 0U)} contains a narrowing conversion from unsigned int to int (and thus is ill-formed), unless expr is a constant expression, in which case the entire expression (expr, 0U) is a constant expression whose evaluated value fits into the type int.
The following is an implementation of is_constexpr for functions, not for arbitrary expressions, for C++11 and C++17. It requires the arguments to the function you want to test to be default constructible, though.
#include <type_traits>
struct A {}; // don't make it too easy, use a UDT
A f1(A a) { return a; } // is_constexpr -> false
constexpr A f2(A a) { return a; } // is_constexpr -> true
// The following turns anything (in our case a value of A) into an int.
// This is necessary because non-type template arguments must be integral
// (likely to change with C++20).
template <class T> constexpr int make_int(T &&) { return 0; }
// Helper to turn some function type (e.g. int(float)) into a function
// pointer type (e.g. int (*)(float)).
template <class T> struct signature_from;
template <class R, class... Args> struct signature_from<R(Args...)> {
using type = R(*)(Args...);
};
// See std::void_t for the idea. This does it for ints instead of types.
template <int...> using void_from_int = void;
// The fallback case: F is not a function pointer to a constexpr function
template <class T, typename signature_from<T>::type F, class = void_from_int<>>
struct is_constexpr {
static constexpr bool value = false;
};
// If void_from_int<make_int(F(Args()...))> doesn't lead to a substitution
// failure, then this is the preferred specialization. In that case F must
// be a function pointer to a constexpr function. If it is not, it could
// not be used in a template argument.
template <class R, class... Args, typename signature_from<R(Args...)>::type F>
struct is_constexpr<R(Args...), F, void_from_int<make_int(F(Args()...))>>
{
static constexpr bool value = true;
};
// proof that it works:
static_assert(!is_constexpr<A(A), f1>::value, "");
static_assert( is_constexpr<A(A), f2>::value, "");
#if __cplusplus >= 201703
// with C++17 the type of the function can be deduced:
template<auto F> struct is_constexpr2 : is_constexpr<std::remove_pointer_t<decltype(F)>, F> {};
static_assert(!is_constexpr2<f1>::value, "");
static_assert( is_constexpr2<f2>::value, "");
#endif
See it in action at https://godbolt.org/g/rdeQme.
C++20 added std::is_constant_evaluated()
This allows checking if a certain expression is a constant evaluated expression, i.e. being evaluated at compile time.
Usage example:
constexpr int foo(int num) {
// below is true in case the condition is being evaluated at compile time
// side note, using: if constexpr (std::is_constant_evaluated())
// would be evaluated always to true, so you should use a simple if!
if (std::is_constant_evaluated()) {
return foo_compiletime(num);
}
else {
return foo_runtime(num);
}
}
int main() {
constexpr auto t1 = foo(6); // reaches foo_compiletime
const auto t2 = foo(6); // reaches foo_compiletime
int n = rand() % 10;
const auto t3 = foo(n); // reaches foo_runtime
auto t4 = foo(6); // unfortunately, reaches foo_runtime
}
The last call in the example above would reach foo_runtime, since the call is not within a constant expression context (the result is not being used as a constant expression, see also this SO answer).
This may lead to undesired pessimization, compared to the case of leaving the decision to the user, who may call:
auto t4 = foo_compiletime(6);
And the compiler is allowed to perform the operations inside foo_compiletime at compile time, if it is declared as constexpr function, or would be obliged to do that if it is declared consteval. However, once we leave the decision to the compiler, we will reach foo_runtime, unless we explicitly direct the compiler to go for foo_compiletime, by taking the result into a const, constexpr or constinit variable. Which then, in a way, omits the value of having one function for both scenarios, if the user is required to help the compiler peek the right path.
Another possible option for the call to be optimized, is:
constexpr auto temp = foo(6); // foo_compiletime
auto t4 = temp;
But again, we require the user to be aware of the inner behavior of foo, which is not exactly what we want to achieve.
See the pessimization in this code.
See more on that in this great blog post on the subject.
Consider the following code:
template<typename T>
constexpr inline T fma(T a, T b, T c)
{
return a * b + c;
}
This compiles just fine. But why does it? In theory, constexpr functions can only call other constexpr functions. However, there is no guarantee that the operators will be constexpr functions. For example, let's say I have some type with the following interface:
class someType
{
someType operator + (const someType &rhs);
someType operator * (const someType &rhs);
};
The operators + and * are not constexpr. If I write the following code:
fma(someType(), someType(), someType());
It should fail to compile because a constexpr function is calling non-constexpr functions. But it compiles just fine. Why is this?
I'm using MinGW's G++ compiler with the -std=c++0x option.
If you call a constexpr function using non-constant expressions as its arguments, the function is executed on runtime.
If you do this:
constexpr someType dummy = fma(someType(), someType(), someType());
it will fail, since you are forcing the result to be stored in a constexpr type. That can't be done in compile-time, therefore you get a compile error.
Note that this would work if you provided both a constexpr constructor and a constexpr operator+/* in someType.
From section 7.1.5.6 of the C++11 standard:
If the instantiated template specialization of a constexpr function template or member function of a class
template would fail to satisfy the requirements for a constexpr function or constexpr constructor, that
specialization is not a constexpr function or constexpr constructor. [ Note: If the function is a member
function it will still be const as described below. — end note ] If no specialization of the template would
yield a constexpr function or constexpr constructor, the program is ill-formed; no diagnostic required.
This means that a constexpr function template degrades to a non-constexpr function if it is instantiated with template parameters which make it not be a valid constexpr function.
If it wouldn't be a valid constexpr function no matter what template parameters you gave it, then the compiler may complain, but it doesn't have to.
Since templates are mostly checked for errors on use, only when you use it with a type with non constexpr operators it will error.