I previously asked about function overloading based on whether the arguments are constexpr. I'm trying to work around the disappointing answer to that question to make a smarter assert function. This is roughly what I am trying to do:
inline void smart_assert (bool condition) {
if (is_constexpr (condition))
static_assert (condition, "Error!!!");
else
assert (condition);
}
Basically, the idea is that a compile-time check is always better than a run-time check if it's possible to check at compile time. However, due to things like inlining and constant folding, I can't always know whether a compile time check is possible. This means that there may be cases where assert (condition) compiles down to assert(false) and the code is just waiting for me to run it and execute that path before the I find out there is an error.
Therefore, if there were some way to check whether the condition is a constexpr (due to inlining or other optimizations), I could call static_assert when possible, and fall back on a run-time assert otherwise. Fortunately, gcc has the intrinsic __builtin_constant_p (exp), which returns true if exp is a constexpr. I don't know if other compilers have this intrinsic, but I was hoping that this would solve my problem. This is the code that I came up with:
#include <cassert>
#undef IS_CONSTEXPR
#if defined __GNUC__
#define IS_CONSTEXPR(exp) __builtin_constant_p (exp)
#else
#define IS_CONSTEXPR(exp) false
#endif
// TODO: Add other compilers
inline void smart_assert (bool const condition) {
static_assert (!IS_CONSTEXPR(condition) or condition, "Error!!!");
if (!IS_CONSTEXPR(condition))
assert (condition);
}
#undef IS_CONSTEXPR
The static_assert relies on the short circuit behavior of or. If IS_CONSTEXPR is true, then static_assert can be used, and the condition is !true or condition, which is the same as just condition. If IS_CONSTEXPR is false, then static_assert cannot be used, and the condition is !false or condition, which is just the same as true and the static_assert is ignored. If the static_assert cannot be checked because condition is not a constexpr, then I add a run-time assert to my code as a last-ditch effort. However, this does not work, thanks to not being able to use function arguments in a static_assert, even if the arguments are constexpr.
In particular, this is what happens if I try to compile with gcc:
// main.cpp
int main () {
smart_assert (false);
return 0;
}
g++ main.cpp -std=c++0x -O0
Everything is fine, compiles normally. There is no inlining with no optimization, so IS_CONSTEXPR is false and the static_assert is ignored, so I just get a run-time assert statement (that fails). However,
[david#david-desktop test]$ g++ main.cpp -std=c++0x -O1
In file included from main.cpp:1:0:
smart_assert.hpp: In function ‘void smart_assert(bool)’:
smart_assert.hpp:12:3: error: non-constant condition for static assertion
smart_assert.hpp:12:3: error: ‘condition’ is not a constant expression
As soon as I turn on any optimizations and thus potentially allow static_assert to be triggered, it fails because I cannot use function arguments in the static_assert. Is there some way to work around this (even if it means implementing my own static_assert)? I feel my C++ projects could theoretically benefit quite a bit from a smarter assert statement that catches errors as early as possible.
It doesn't seem like making smart_assert a function-like macro will solve the problem in the general case. It will obviously make it work in this simple example, but condition may have come from a function two levels up the call graph (but still becomes known to the compiler as a constexpr due to inlining), which runs into the same problem of using a function parameter in a static_assert.
This should help you start
template<typename T>
constexpr typename remove_reference<T>::type makeprval(T && t) {
return t;
}
#define isprvalconstexpr(e) noexcept(makeprval(e))
Explicit is good, implicit is bad, in general.
The programmer can always try a static_assert.
If the condition can not be evaluated at compile time, then that fails, and the programmer needs to change to assert.
You can make it easier to do that by providing a common form so that the change reduces to e.g. STATIC_ASSERT( x+x == 4 ) → DYNAMIC_ASSERT( x+x == 4 ), just a renaming.
That said, since in your case you only want an optimization of the programmer’s time if that optimization is available, i.e. since you presumably don’t care about getting the same results always with all compilers, you could always try something like …
#include <iostream>
using namespace std;
void foo( void const* ) { cout << "compile time constant" << endl; }
void foo( ... ) { cout << "hm, run time,,," << endl; }
#define CHECK( e ) cout << #e << " is "; foo( long((e)-(e)) )
int main()
{
int x = 2134;
int const y = 2134;
CHECK( x );
CHECK( y );
}
If you do, then please let us know how it panned out.
Note: the above code does produce different results with MSVC 10.0 and g++ 4.6.
Update: I wondered how the comment about how the code above works, got so many upvotes. I thought maybe he's saying something I simply don't understand. So I set down to do the OP's work, checking how the idea fared.
At this point I think that if the constexpr function thing can be be made to work with g++, then it's possible to solve the problem also for g++, otherwise, only for other compilers.
The above is as far as I got with g++ support. This works nicely (solves the OP's problem) for Visual C++, using the idea I presented. But not with g++:
#include <assert.h>
#include <iostream>
using namespace std;
#ifdef __GNUC__
namespace detail {
typedef double (&Yes)[1];
typedef double (&No)[2];
template< unsigned n >
Yes foo( char const (&)[n] );
No foo( ... );
} // namespace detail
#define CASSERT( e ) \
do { \
char a[1 + ((e)-(e))]; \
enum { isConstExpr = sizeof( detail::foo( a ) ) == sizeof( detail::Yes ) }; \
cout << "isConstExpr = " << boolalpha << !!isConstExpr << endl; \
(void)(isConstExpr? 1/!!(e) : (assert( e ), 0)); \
} while( false )
#else
namespace detail {
struct IsConstExpr
{
typedef double (&YesType)[1];
typedef double (&NoType)[2];
static YesType check( void const* );
static NoType check( ... );
};
} // namespace detail
#define CASSERT( e ) \
do { \
enum { isConstExpr = \
(sizeof( detail::IsConstExpr::check( e - e ) ) == \
sizeof( detail::IsConstExpr::YesType )) }; \
(void)(isConstExpr? 1/!!(e) : (assert( e ), 0)); \
} while( false )
#endif
int main()
{
#if defined( STATIC_TRUE )
enum { x = true };
CASSERT( x );
cout << "This should be displayed, OK." << endl;
#elif defined( STATIC_FALSE )
enum { x = false };
CASSERT( x );
cerr << "!This should not even have compiled." << endl;
#elif defined( DYNAMIC_TRUE )
bool x = true;
CASSERT( x );
cout << "This should be displayed, OK." << endl;
#elif defined( DYNAMIC_FALSE )
bool x = false;
CASSERT( x );
cout << "!Should already have asserted." << endl;
#else
#error "Hey, u must define a test case symbol."
#endif
}
Example of the problem with g++:
[D:\dev\test]
> g++ foo.cpp -Werror=div-by-zero -D DYNAMIC_FALSE
[D:\dev\test]
> a
isConstExpr = true
!Should already have asserted.
[D:\dev\test]
> _
That is, g++ reports (even via its intrinsic function, and even wrt. creating VLA or not) that a non- const` variable that it knows the value of, is constant, but then it fails to apply that knowledge for integer division, so that it then fails to produce warning.
Argh.
Update 2: Well I'm dumb: of course the macro can just add an ordinary assert to have there in any case. Since the OP is only interested in getting the static assert when it's available, which isn't for g++ in some corner cases. Problem solved, and was solved originally.
How is the answer to the other question disappointing? It implements almost exactly what you presently describe, except for the way the compiler prints the text in the diagnostic message.
The reason it needs to be done with throw is that compile-time evaluation of constexpr in a context that could be evaluated at runtime is optional. For example, the implementation could choose to let you step through the constexpr code in debugging mode.
constexpr is a weak attribute of functions (declaration specifier) that cannot change the resulting value of an expression using the function. It is a guarantee that the semantic meaning at runtime is fixed at compile time, but doesn't allow you to specify a special compile-time shortcut.
As for flagging invalid conditions, throw is a subexpression which is invalid as a constant expression, except when hidden in the unevaluated side of ?:, &&, or ||. The language guarantees that this will be flagged at compile time, even if the debugger lets you step through it at runtime, and only if the flag is really triggered.
The language gets things right here. Unfortunately that cannot be reconciled with the special diagnostic message feature of static_assert or branching on constexpr-ness.
Related
Since the extended versions of constexpr (I think from C++14) you can declare constexpr functions that could be used as "real" constexpr. That is, the code is executed at compile time or can behave as inline functions. So when can have this program:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
The result is:
7
7
7
So far so good.
Is there a way (possibly standard) to know inside foo(const int s) if the function is executed at compile time or at runtime?
EDIT: Also is it possible to know at runtime if a function was evaluated at compile time?
C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.
The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:
template <class T>
constexpr void test_helper(T&&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).
So now let's define this:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.
The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.
I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.
If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.
This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.
Within a constexpr function, you couldn't tell if you are being evaluated in a constexpr context prior to c++20. Since c++20, this functionalty was added -- constexpr bool std::is_constant_evaluated() will tell you if you are being called in a constexpr context.
Outside a constexpr function, there are a number of ways to determine if a call to a function with a certain set of arguments would be evaluated in a constexpr context. The easiest would be to use the result in a context requiring constexpr.
Assuming your constexpr expression returns a non-void integral or pointer type (including function pointer):
#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
then CONSTEXPR_EVAL( bar(foo, true) ) will fail to compile if bar(foo, true) cannot be evaluated at compile time, and if it can be evaluated at compile time it returns that value.
Other tricks involving noexcept (a function evaluated at compile time is noexcept) can work (see #NirFriedman's answer).
Based on the information in this discussion, I crafted the following minimal example:
template <class T>
constexpr void test_helper(T &&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
constexpr void test(){
static_assert(IS_CONSTEXPR(10), "asdfadsf");
constexpr const int x = 10;
static_assert(IS_CONSTEXPR(x), "asdfadsf");
int y;
static_assert(IS_CONSTEXPR(y), "asdfadsf");
}
int main(){
test();
return 0;
}
To my disappointment, It it fails to compile at each of the static_asserts. see https://www.godbolt.org/z/Tr3z93M3s
Sorry for spoiling the party, but there is certainly no standard way of doing this. Under the as-if rule, the compiler could emit code that calculates the result at run time even in such cases where it has already been forced to calculate it at compile time in a different context. Anything that can be done at compile time can be done again at run time, right? And the calculation has already been proven not to throw.
By extension, then, any standard-compliant IS_REALLY_CONSTEXPR or is_really_constexpr check cannot disprove that the exact same call, or for that matter, the value of the exact same constexpr symbol involves a run time calculation.
Of course there usually isn't any reason to repeat a calculation at run time that can be done or even has already been done at compile time, but the question was about telling whether the compiler uses the precalculated result, and there isn't one.
Now you did say possibly standard, so in effect your best bet is probably to test one of the provided solutions with your compiler of choice and hope that it behaves consistently. (Or reading the source code if it is open/public source and you are so inclined.)
Since the extended versions of constexpr (I think from C++14) you can declare constexpr functions that could be used as "real" constexpr. That is, the code is executed at compile time or can behave as inline functions. So when can have this program:
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
return 0;
}
The result is:
7
7
7
So far so good.
Is there a way (possibly standard) to know inside foo(const int s) if the function is executed at compile time or at runtime?
EDIT: Also is it possible to know at runtime if a function was evaluated at compile time?
C++20 introduces is_constant_evaluated, defined in header <type_traits>, which addresses this issue.
constexpr int foo(int s)
{
if (std::is_constant_evaluated()) // note: not "if constexpr"
/* evaluated at compile time */;
else
/* evaluated at run time */;
}
Note that here the ordinary if is used instead of if constexpr. If you use if constexpr, then the condition has to be evaluated at compile time, so is_constant_evaluated always returns true, rendering the test useless.
The technique listed works, but since it uses static_assert it is not sfinae friendly. A better way (in theory, you'll see what I mean) to do this is to check whether a function is noexcept. Why? Because, constant expressions are always noexcept, even if the functions are not marked as such. So, consider the following code:
template <class T>
constexpr void test_helper(T&&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
test_helper is constexpr, so it will be a constant expression as long as its argument is. If it's a constant expression, it will be noexcept, but otherwise it won't be (since it isn't marked as such).
So now let's define this:
double bar(double x) { return x; }
constexpr double foo(double x, bool b) {
if (b) return x;
else return bar(x);
}
foo is only noexcept if the x is a constant expression, and b is true; if the boolean is false then we call a non constexpr function, ruining our constexpr-ness. So, let's test this:
double d = 0.0;
constexpr auto x = IS_CONSTEXPR(foo(3.0, true));
constexpr auto y = IS_CONSTEXPR(foo(3.0, false));
constexpr auto z = IS_CONSTEXPR(foo(d, true));
std::cerr << x << y << z;
It compiles, great! This gives us compile time booleans (not compile failures), which can be used for sfinae, for example.
The catch? Well, clang has a multi-year bug, and doesn't handle this correctly. gcc however, does. Live example: http://coliru.stacked-crooked.com/a/e7b037932c358149. It prints "100", as it should.
I think the canonical way to do that is with static_assert. static_asserts are evaluated at compile time, so they will break the build if their condition is false.
#include <iostream>
constexpr int foo(const int s) {
return s + 4;
}
int main()
{
std::cout << foo(3) << std::endl;
const int bar = 3;
std::cout << foo(bar) << std::endl;
constexpr int a = 3;
std::cout << foo(a) << std::endl;
static_assert(foo(3) == 7, "Literal failed");
static_assert(foo(bar) == 7, "const int failed");
static_assert(foo(a) == 7, "constexpr int failed");
return 0;
}
clang++ -std=c++14 so1.cpp compiles fine for me, showing that everything works as expected.
If you can use C++20, there is std::is_constant_evaluated which does exactly what you want. std::is_constant_evaluated is typically implemented using a compiler intrinsic.
This is called __builtin_is_constant_evaluated in GCC and clang, so you can implement your own "safe" wrapper around it, even in C++17 and lower.
// if C++20, we will need a <type_traits> include for std::is_constant_evaluated
#if __cplusplus >= 202002L
#include <type_traits>
#endif
constexpr bool is_constant_evaluated() {
#if __cplusplus >= 202002L
return std::is_constant_evaluated();
#elif defined(__GNUC__) // defined for both GCC and clang
return __builtin_is_constant_evaluated();
#else
// If the builtin is not available, return a pessimistic result.
// This way callers will implement everything in a constexpr way.
return true;
#endif
}
Note that this builtin is still relatively new (GCC 9.0+) so you might also want to detect the compiler version.
Within a constexpr function, you couldn't tell if you are being evaluated in a constexpr context prior to c++20. Since c++20, this functionalty was added -- constexpr bool std::is_constant_evaluated() will tell you if you are being called in a constexpr context.
Outside a constexpr function, there are a number of ways to determine if a call to a function with a certain set of arguments would be evaluated in a constexpr context. The easiest would be to use the result in a context requiring constexpr.
Assuming your constexpr expression returns a non-void integral or pointer type (including function pointer):
#define CONSTEXPR_EVAL(...) \
std::integral_constant< \
std::decay_t<decltype(__VA_ARGS__)>, \
__VA_ARGS__ \
>::value
then CONSTEXPR_EVAL( bar(foo, true) ) will fail to compile if bar(foo, true) cannot be evaluated at compile time, and if it can be evaluated at compile time it returns that value.
Other tricks involving noexcept (a function evaluated at compile time is noexcept) can work (see #NirFriedman's answer).
Based on the information in this discussion, I crafted the following minimal example:
template <class T>
constexpr void test_helper(T &&) {}
#define IS_CONSTEXPR(...) noexcept(test_helper(__VA_ARGS__))
constexpr void test(){
static_assert(IS_CONSTEXPR(10), "asdfadsf");
constexpr const int x = 10;
static_assert(IS_CONSTEXPR(x), "asdfadsf");
int y;
static_assert(IS_CONSTEXPR(y), "asdfadsf");
}
int main(){
test();
return 0;
}
To my disappointment, It it fails to compile at each of the static_asserts. see https://www.godbolt.org/z/Tr3z93M3s
Sorry for spoiling the party, but there is certainly no standard way of doing this. Under the as-if rule, the compiler could emit code that calculates the result at run time even in such cases where it has already been forced to calculate it at compile time in a different context. Anything that can be done at compile time can be done again at run time, right? And the calculation has already been proven not to throw.
By extension, then, any standard-compliant IS_REALLY_CONSTEXPR or is_really_constexpr check cannot disprove that the exact same call, or for that matter, the value of the exact same constexpr symbol involves a run time calculation.
Of course there usually isn't any reason to repeat a calculation at run time that can be done or even has already been done at compile time, but the question was about telling whether the compiler uses the precalculated result, and there isn't one.
Now you did say possibly standard, so in effect your best bet is probably to test one of the provided solutions with your compiler of choice and hope that it behaves consistently. (Or reading the source code if it is open/public source and you are so inclined.)
Please note C++03! any C++11 solutions are not good for me, but do post them just for knowledge sake.
I know the preprocessor can do things like:
#define FOO 4
#if FOO == 4
cout<<"hi"<<endl;
#endif
What I need is:
#define BAR(X)\
#if X == 4\
cout<<"hi"<<endl;\
#endif
main.cpp
BAR(4)
I don't see why all the needed information wouldn't be available in preprocessor time.
So, Please tell me how to achieve this kind of behavior.
edit 1:
A normal if condition won't work for my case, because I also do things like:
#define BAR(X)\
#if X == 4\
int poop;
#elif
double poop;
#endif
As you've discovered, you can't do this in the way that you've attempted. Macro expansion simply doesn't have inline conditional evaluation, so you'd have to create multiple macros instead.
However, if you're just trying to "optimise" normal code flow, you can rely on your compiler's optimizations. Consider this:
if (true) {
std::cout << "Hi\n";
}
The resulting program will not have any conditional checks in it, because true is always truthy.
Similarly:
if (false) {
std::cout << "Hi\n";
}
The resulting program will not contain any code to produce output, because false is never truthy.
Similarly:
if (4 != 4) {
std::cout << "Hi\n";
}
The program will still not contain the std::cout code.
In many cases, you may use this fact to keep your code simple and achieve your desired effect:
#define BAR(X) \
if ((X) == 4) {
std::cout << "hi" << std::endl;\
}
The constraint here, of course, is that an if statement must be valid at the place you write BAR(5), or BAR(42) or BAR(999).
This is also flexible in that now you can use a runtime value (like BAR(i)) and, although the conditional can no longer be collapsed at compile-time, in such a case you'd have no reason to expect that anyway.
I take this approach in my logging macro: the macro, when called for LOG_LEVEL_DEBUG, expands to a conditional that is statically known never to match, in release builds.
The idea is to let the compiler do the optimising.
You're also going to want to consider using a little macro expansion trick to avoid problems with subsequent else clauses.
You can do this with the preprocessor if the domain of values for the conditional parameter is well-known (and preferably small). For example, supposing the parameter can only have the values 0 and 1:
#define DOIT_0(X)
#define DOIT_1(X) X
#define CONCAT_(X, Y) X ## Y
#define MAYBE(X) CONCAT_(DOIT_, X)
#define BAR(X) MAYBE(X)( cout<<"hi"<<endl; )
#define YESNO 0
BAR(YESNO)
Live on coliru.
Beware of unprotected commas in the argument to BAR.
For equality checks, again over a small range:
#define CONCAT3_(X,Y,Z) X ## Y ## Z
#define EQUAL_0_0(X) X
#define EQUAL_1_1(X) X
#define EQUAL_1_1(X) X
#define EQUAL_0_1(X)
#define EQUAL_0_2(X)
#define EQUAL_1_0(X)
#define EQUAL_1_2(X)
#define EQUAL_2_0(X)
#define EQUAL_2_1(X)
#define DO_IF_EQUAL(X, Y) CONCAT3_(EQUAL_, X, Y)
#define BAR(X) DO_IF_EQUAL(X, 2) ( std::cout << "hi\n"; )
If you can use Boost, you could do this with Boost.Preprocessor:
#define BAR(X) BOOST_PP_EXPR_IF(BOOST_PP_EQUAL(X, 4), cout << "hi" << endl;)
Some answers here were better than others.
The one I accepted was posted by Christian Kiewiet in a comment, but it was the most accurate for my purpose.
Here is the expanded version:
useCases.h
enum UseCases{
useCase1=0,
useCase2,
useCaseNumber//always last for iterations
}
specializer.h
#include "useCases.h"
<template UseCases theCase>
struct StaticCase{
//empty, thus accidents calling from this can't happen
}
//specialization
template<>
class StaticCase<UseCases::useCase1>{
typedef int T;
static foo(T arg){cout<<"case1";};
}
template<>
class StaticCase<UseCases::useCase2>{
typedef double T;
static foo(){cout<<"case2";};
}
Now, I can do
#define BAR1(useCase) StaticCase<useCase>::foo();
or
#define BAR2(useCase) StaticCase<useCase>::T var;
and the call:
BAR1(UseCases::useCase1)//output - case1
BAR1(UseCases::useCase2)//output - case2
When working on a large legacy code base, I today suspected a duplicate definition, but the dependency was not obvious to me human since it depended on a lots of compile-time calculations.
enum { MAX_ITEMS = 4 }; // defined somewhere in my code universe
enum { ITEMS_MAX = COMPLICATED_CALCULATIONS }; // somewhere else
I remembered some cases with analogous sizeof questions, when I let the compiler speak.
I usually put some ad-hoc formulations like this in the code (in the IDE), then I press [Alt]+[F9]:
void check() {
char bla[MAX_ITEMS == ITEMS_MAX]; // compiler-error shows difference
// ...but it causes a compiler warning about bla being never used
}
...and that's only because my compiler (Borland C++ 5.6.4) lazy evaluates the typedef for arrays with non-literal dimension:
typedef char bla[0]; // immediate compiler error
typedef char bla[0 != 0]; // obvious, but no compiler error HERE
Is there a really easy-to-memorize way for checks like this? And, please don't blame an old brave compiler ;-)
This works:
#define STATIC_ASSERT(x) typedef char foo[(x) ? 1 : -1];
I actually use the following setup borrowed from Boost, the purpose of this is to give each foo its own line number (otherwise a multiple definition error can happen):
#define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y )
#define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y)
#define BOOST_DO_JOIN2( X, Y ) X##Y
#define STATIC_ASSERT(x) \
typedef char BOOST_JOIN(violation_on_line_,__LINE__) [(x) ? 1 : -1];
You should try if BOOST_STATIC_ASSERT works on your compiler.
I'm writing C++ using the MinGW GNU compiler and the problem occurs when I try to use an externally defined integer variable as a case in a switch statement. I get the following compiler error: "case label does not reduce to an integer constant".
Because I've defined the integer variable as extern I believe that it should compile, does anyone know what the problem may be?
Below is an example:
test.cpp
#include <iostream>
#include "x_def.h"
int main()
{
std::cout << "Main Entered" << std::endl;
switch(0)
{
case test_int:
std::cout << "Case X" << std::endl;
break;
default:
std::cout << "Case Default" << std::endl;
break;
}
return 0;
}
x_def.h
extern const int test_int;
x_def.cpp
const int test_int = 0;
This code will compile correctly on Visual C++ 2008. Furthermore a Montanan friend of mine checked the ISO C++ standard and it appears that any const-integer expression should work. Is this possibly a compiler bug or have I missed something obvious?
Here's my compiler version information:
Reading specs from C:/MinGW/bin/../lib/gcc/mingw32/3.4.5/specs
Configured with: ../gcc-3.4.5-20060117-3/configure --with-gcc --with-gnu-ld --with-gnu-as --host=mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls --enable-languages=c,c++,f77,ada,objc,java --disable-win32-registry --disable-shared --enable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x --enable-java-gc=boehm --disable-libgcj-debug --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug
Thread model: win32
gcc version 3.4.5 (mingw-vista special r3)
A case label requires an integral constant expression which have strict requirements that enable their value to be determined at compile time at the point of use.
From 5.19 [expr.const], "an integral constant expression can involve only literals (2.13), enumerators, const variables or static data members of integral or enumeration types initialized with constant expressions (8.5),...".
At the point at which you use test_int where a constant expression is required, it is a const variable declared extern and without any initializer and does not meet the requirements for a constant expression, despite the fact that you do actually initialize it with a integral constant expression in another translation unit. (*This is not completely clear from the wording of the standard but is my current interpretation of it.)
The restrictions in the standard disallow usages such as:
void f(int a, int b)
{
const int c = b;
switch (a)
{
case c:
//...
}
}
In your example, when the compiler is compiling test.cpp, it has no way to determine what the initializer might be in x_def.cpp. You might have done:
const int test_int = (int)time();
Clearly, in neither of these examples could the value of the const int be determined at compile time which is the intention for integral constant expressions.
Case labels have to be compile-time constants. That means the compiler must be able to substitute the value at compile-time. Although your values are constant, the compiler can't know their values until at least link-time.
VC++ is right, and g++ is wrong. A case label is required to be an integral constant expression (§6.4.2/2) and a const variable of integer type initialized with a constant expression is a constant expression (§5.19/1).
Edit:mostly for Pavel, and his suggestion of a possible DR. §5.19/2 has been completely rewritten already. C++0x adds a whole new concept of a constexpr that expands what's considered a constant expression considerably. For example, under the current standard, something like:
int x() { return 10; }
const int y = x();
y is not a constant expression. We can all easily see that it's (indirectly) initialized with a literal 10, but the compiler still can't allow it as a constant expression. Under the new standard, it'll be possible designate x() as a constexpr, and y will be a constant expression.
As it's formulated in N2960, §5.19/2 says an expression is a constant expression unless it uses something from the following list. It then gives about a page-long list, but using a const variable that isn't initialized in the current compilation unit doesn't seem to be one of them. [Edit: see below -- reading CWG Issue 721, I've changed my mind.]
As far as VC++ being right and g++ wrong, I meant only in this very specific respect. There's no question that both are "wrong" if you're talking about getting every part of the standard correct. I doubt anybody's even working on implementing export for either one.
export does, however, point out a degree to which C++ seems willing to postpone decisions until link time. Two-phase name lookup means that when an exported template is compiled, there's a lot more than just constant expressions that it doesn't know for sure. It might not even know whether a particular name refers to a function or an object -- but there's no question that the standard does require exactly that. The issue at hand strikes me as a substantially simpler one to deal with.
Edit: I did a bit of searching, and found Core Working Group Issue 721. Jame's question parallels the one at hand quite closely ("However, this does not require, as it presumably should, that the initialization occur in the same translation unit and precede the constant expression..."). The proposed resolution adds the phrase: "...with a preceding initialization...". At least as I read it, that means that the committee agreed that under the current standard, the code must be accepted, but under the new standard it's not allowed.
That wording was agreed upon in July of this year, but doesn't (yet?) appear in N2960, which I believe is the most recent draft of C++0x.
I cannot reproduce this on a trivial example using VC++2008:
test.cpp:
extern const int n;
int main() {
switch (0) {
case n: break;
}
}
test2.cpp:
extern const int n = 123;
compile with:
cl.exe test.cpp test2.cpp
output:
test.cpp(4) : error C2051: case expression not constant
MS compiler is being a bit naughty here. When you compile the the constant initialization and the case statement using the constant in the same compilation unit it works out the constant value at compile time.
Once you attempt to use the extern const outside of the compilation unit where it's initialised (i.e. the cpp file containing initialization or any of the files it includes) the compiler will barf with pretty much the same error. Fred Larson is correct the compiler shouldn't know the constant value until link time and thus it must not be acceptable as a switch constant, it's just MS compiler cheats a little bit.
The solution to your problem would be to use macros, is there any reason why you don't want to #define the constant?
Here's a simpler test:
test_int.cpp:
const int test_int = 10;
main.cpp:
#include <iostream>
using std::cout;
using std::endl;
extern const int test_int;
int main() {
cout << test_int << endl;
return 0;
}
In G++, I get an undefined reference. However, doing the same thing in C works. According to http://gcc.gnu.org/ml/gcc/2005-06/msg00325.html , a const variable implicitly has internal linkage in C++. This doesn't appear to be the case in C.
I'm using a "gcc (SUSE Linux) 4.3.2" and having a similar effect, that still is a bit stranger.
My definitions are:
namespace operations{
const cOpDummy OpDummy();
const cInitOperator InitOperator();
};
const unsigned long ulNumberOfOperations = 2;
const cOperation * arrayOperations[] = {
& (operations::OpDummy),
& (operations::InitOperator)
};
And the extern declarations in an other file are:
extern const unsigned long ulNumberOfOperations;
extern const cOperation * arrayOperations[];
The funny thing is: The compiler gives just for "ulNumberOfOperations" "undefined reference to ulNumberOfOperations", but is Ok with "arrayOperations[]".
My workaround is to declare "ulNumberOfOperations" not constant.
Since c++11 you could build a little template framework to give you a syntax like this:
void test(int a, int x, int y, int z)
{
std::cout << "given " << a << ", choosing ";
given(a)
.when(x, [] { std::cout << "x\n"; })
.when(y, [] { std::cout << "y\n"; })
.when(z, [] { std::cout << "z\n"; })
.when(any_other, [] { std::cout << "none of the above\n"; });
}
Full demo:
#include <iostream>
struct any_object {};
constexpr auto any_other = any_object {};
template<class Expr>
struct when_object
{
template<class T, class F>
constexpr when_object& when(T const& value, F&& f)
{
if (not executed and expr == value) {
executed = true;
f();
}
return *this;
}
template<class F>
constexpr void when(any_object, F&& f)
{
if (not executed) {
executed = true;
f();
}
}
Expr const& expr;
bool executed = false;
};
template<class Expr>
constexpr auto given(Expr const& expr)
{
return when_object<Expr> {expr};
}
void test(int a, int x, int y, int z)
{
std::cout << "given " << a << ", choosing ";
given(a)
.when(x, [] { std::cout << "x\n"; })
.when(y, [] { std::cout << "y\n"; })
.when(z, [] { std::cout << "z\n"; })
.when(any_other, [] { std::cout << "none of the above\n"; });
}
int main()
{
test(4, 4, 5, 6);
test(4, 3, 4, 5);
test(4, 2, 3, 4);
test(1, 2, 3, 4);
}
expected results:
given 4, choosing x
given 4, choosing y
given 4, choosing z
given 1, choosing none of the above