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.
相关问题
- Sorting 3 numbers without branching [closed]
- How to compile C++ code in GDB?
- Why does const allow implicit conversion of refere
- thread_local variables initialization
- What uses more memory in c++? An 2 ints or 2 funct
相关文章
- Class layout in C++: Why are members sometimes ord
- How to mock methods return object with deleted cop
- Which is the best way to multiply a large and spar
- C++ default constructor does not initialize pointe
- Selecting only the first few characters in a strin
- What exactly do pointers store? (C++)
- Converting glm::lookat matrix to quaternion and ba
- What is the correct way to declare and use a FILE
I once wrote it (EDIT: see below for limitations and explanations). From https://stackoverflow.com/a/10287598/34509 :
However there are many kinds of constant expressions. The above answer detects prvalue constant expressions.
Explanation
The
noexcept(e)
expression givesfalse
iffe
containsthrow
expression,dynamic_cast
ortypeid
.Note that the function template
makeprval
is not declarednoexcept
, 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 athrow
and a throwabledynamic_cast
ortypeid
aren't allowed in constant expressions aswell, so this is fine.Limitations
Unfortunately there is a suble 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:In the above
atest
is false, even though the initialization ofa
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.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.See it in action at https://godbolt.org/g/rdeQme.
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:(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:
Live demonstration.
The key here is that
int{(expr, 0U)}
contains a narrowing conversion fromunsigned int
toint
(and thus is ill-formed), unlessexpr
is a constant expression, in which case the entire expression(expr, 0U)
is a constant expression whose evaluated value fits into the typeint
.Let's do some naive play with the SFINAE idiom:
The code above is syntactically wrong, but it will give us some insight. Let's try to make use of it:
The compiler says:
Now the problem is obvious: the parameter of the template is
T = int (*)();
It means that
constexpr
is not part of type and we cannot detect it.