So, in a non-class type of situation, I can do something like this:
int val_to_check = 0;
int some_func(int param) {
assert(val_to_check == 0);
return param*param+param;
}
int main() {
printf("Val: %i\n", some_func(rand()));
return 0;
}
If val_to_check is declared const instead, the assertion can be folded away by the compiler.
I'm curious if it's possible to get a similar constant folding with a member variable of a class. For example, can I do something like:
class Test {
public:
Test(int val) : val_(val) {}
int some_func(int param) {
assert(val_ == 0);
return param*param+param;
}
private:
const int val_;
};
So val_ must be known when the class is defined, a-la:
Test my_test(0);
printf("Val: %i\n", my_test.some_func(rand()));
(I know these are contrived examples). It seems like it should be possible to fold the assertions away sometimes, but the simple examples I've tested don't seem to do it. The best I've gotten is moving the assertion code to the end of the function (when compiling w/ -O3)
In the class example you provided, there's no way for the compiler to assume the constant is zero because you have two runtime variables:
Your const int val_ is only constant for each instance of the class so it can never optimise the class's function code since it must cater for every case.
The example instantiation doesn't provide a literal constant, it provides the result of rand() which is variable. It may be possible for it to optimise it out if it knows the ONLY val_ ever being provided to all instances of that class is zero.
Have you tried providing a constant to the constructor to see if it optimises it out?
In C++, there is the notion of a "constant expression" (5.19). This is a literal expression, an arithmetic expression only involving constant expressions, or a value of a variable initialized statically with a constant expression. The compiler is able to determine the value of such an expression at compile time.
In your case, val_ is not a "constant expression", since it may have different values depending on the object it is a member of. For the out-of-line version of some_func, you probably agree that the compiler cannot know that it is a constant. For the inline version, it would be possible to determine the value of val_, assuming you also have the complete source code of all constructors analyzed. Whether the compiler is able to make this analysis is a quality-of-implementation issue - your compiler apparently is not able to.
val_ is const for the instance, not for all instances. If you actually want it to be the same for all instances, then you can make it static const and that would allow the compiler to optimize it out which is really what is happening in your first example with a global made const.
As a side note, your examples are subject to integer overflow.
-O2 seems to do the trick for me:
% cat foo.cxx
#include <cstdio>
#include <cstdlib>
#include <cassert>
class Test {
public:
Test(int val) : val_(val) {}
int some_func(int param) {
assert(val_ == 0);
return param*param+param;
}
private:
const int val_;
};
int main() {
Test my_test(0);
printf("Val: %d\n", my_test.some_func(rand()));
return 0;
}
% g++ -S foo.cxx && grep assert foo.s ; echo $?
.ascii "%s:%u: failed assertion `%s'\12\0"
0
% g++ -O2 -S foo.cxx && grep assert foo.s ; echo $?
1
If you want an assert that you're sure gets folded away, you might want to look up boost::static_assert.
Right now, I'm rather bothered by the basic notion of the design: you're allowing the user of the class to supply a value, but then asserting that it must be one particular value. If only one value is right, why have them supply it at all? Why not just use the right value and be done with it?
Keep in mind that the general idea of an assert is that its failure should NOT signal something like incorrect input. It should only be used to signal a fundamental problem with the program itself -- that there's faulty logic somewhere, or something on that order.
On the other hand, maybe you're dealing with a situation where different values are allowed, but you want to take different actions (or implement the same actions differently) for one particular value. To get the assert folded away, it's obviously going to have to be a compile-time constant.
That being the case, I'd consider creating a template, with that value as a non-type template parameter. Specialize the template for the value you want to implement specially. This gives roughly the effect you seem to want, but enforces the fact that the test for that value has to happen at compile time, not run time. Instead of writing run-time code and hoping the compiler's smart enough to handle it at compile time, you write a compile-time match explicitly.
Related
I was reading about constexpr here:
The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.
When I first read this sentence, it made perfect sense to me. However, recently I've come across some code that completely threw me off. I've reconstructed a simple example below:
#include <iostream>
void MysteryFunction(int *p);
constexpr int PlusOne(int input) {
return input + 1;
}
int main() {
int i = 0;
MysteryFunction(&i);
std::cout << PlusOne(i) << std::endl;
return 0;
}
Looking at this code, there is no way for me to say what the result of PlusOne(i) should be, however it actually compiles! (Of course linking will fail, but g++ -std=c++11 -c succeeds without error.)
What would be the correct interpretation of "possible to evaluate the value of the function at compile time"?
The quoted wording is a little misleading in a sense. If you just take PlusOne in isolation, and observe its logic, and assume that the inputs are known at compile-time, then the calculations therein can also be performed at compile-time. Slapping the constexpr keyword on it ensures that we maintain this lovely state and everything's fine.
But if the input isn't known at compile-time then it's still just a normal function and will be called at runtime.
So the constexpr is a property of the function ("possible to evaluate at compile time" for some input, not for all input) not of your function/input combination in this specific case (so not for this particular input either).
It's a bit like how a function could take a const int& but that doesn't mean the original object had to be const. Here, similarly, constexpr adds constraints onto the function, without adding constraints onto the function's input.
Admittedly it's all a giant, confusing, nebulous mess (C++! Yay!). Just remember, your code describes the meaning of a program! It's not a direct recipe for machine instructions at different phases of compilation.
(To really enforce this you'd have the integer be a template argument.)
A constexpr function may be called within a constant expression, provided that the other requirements for the evaluation of the constant expression are met. It may also be called within an expression that is not a constant expression, in which case it behaves the same as if it had not been declared with constexpr. As the code in your question demonstrates, the result of calling a constexpr function is not automatically a constant expression.
What would be the correct interpretation of "possible to evaluate the value of the function at compile time"?
If all the arguments to the function are evaluatable at compile time, then the return value of the function can be evaluated at compile time.
However, if the values of the arguments to the function are known only at run time, then the retun value of the function can only be evaluated at run time.
Hence, it possible to evaluate the value of the function at compile time but it is not a requirement.
All the answers are correct, but I want to give one short example that I use to explain how ridiculously unintuitive constexpr is.
#include <cstdlib>
constexpr int fun(int i){
if (i==42){
return 47;
} else {
return rand();
}
}
int main()
{
int arr[fun(42)];
}
As a side note:
some people find constexpr status unsatisfying so they proposed constexpr! keyword addition to the language.
I have a type T (for simplicity you may assume it's integral). I want to write some magic piece of code, after which I can use the identifier foo in any context in which I could use a value previous declared to have type T - with no necessary conversion. I also want decltype(T) to be T, and no less importantly - I want a guarantee that no space will ever be allocated for foo, it will only be relevant at compile time.
Is there a way to achieve this other than using #DEFINE? AFAICT, constexpr const isn't guaranteed to avoiding space allocation.
There is no way to do that, because standard does not force compilers to optimize anything. constexpr variables are very likely to be optimized if they are not odr-used.
If you can relax some of your requirements:
enum : T
{
foo = some_value
};
Altough you create new type here, std::underlying_type<> will evaluate to T and you can use it without conversions where T is expected (with usual integer conversion rules). It also does not require function calling syntax (a constexpr function would be probably the best way to avoid space allocation, but it forces you to change the syntax from T val = foo to T val = foo(), which may or may not be acceptable).
If writing a function is good enough, here is a minimal example:
struct T { int value; };
constexpr T foo() { return { 42 }; }
int main()
{
return foo().value;
}
Compiled with -std=c++17 -O3:
main:
mov eax, 42
ret
The following condition is met:
#include <type_traits>
static_assert(std::is_same_v<T, decltype(foo())>);
Just to be clear, there is no guarantee whatsoever that your compiler and linker will remove the foo code from the final assembly, this is only highly probable.
However, it is guaranteed than the definition of function foo will only impact, if it does, the executable size and not the allocated storage.
I was disappointed to learn recently that C does not allow assignment of variables during static variable initialization, unlike C++. E.g. the following code compiles as C++...
#include <stdio.h>
int foo()
{
return 1;
}
static int g_i = foo();
int main( int argc, char* argv[] )
{
printf( "%d\n", g_i );
return 0;
}
...but issues the following error with a C compiler:
>cc -g main.c
main.c:8:1: error: initializer element is not constant
static int g_i = foo();
^
I thought I could be clever by using the comma operator a-la:
static int g_i = ( foo(), 1 );
...but the compiler seemed unimpressed with my attempted cleverness, and output effectively the same error:
>cc -c main.c
main.c:8:1: error: initializer element is not constant
static int g_i = ( foo(), 1 );
^
:(
Q: Why does use of the comma operator not work? I may be unaware of some subtlety, but my understanding led me to think it should have worked: the C compiler is demanding g_i be initialzed to a compiletime constant; supposedly the comma operator would have offered me evaluation of the code left of the comma, but assignment of the code right of the comma, which is a compiletime constant.
Q: Are there any hacks - I don't care how dirty - that would allow assignment to g_i the return value of foo() to g_i?
This is a simplified representation of a C program where I really just want to call a function before main() - I don't care about the return value, but it's a more complicated problem to call a void function before main(), which I would rather sidestep altogether by using an int function whose value is assigned to a throwaway static int variable.
C does not support dynamic initialization. For this reason, static objects are required to be initialized with constant expressions. Constant expressions are not allowed to involve any run-time computations, even if these computations do not affect the final value of the expression. Your expression with comma operator is not a constant expression.
(Moreover, comma operator is prohibited in C constant expressions even if you don't call any functions from them. E.g. even something as trivial as (1, 2, 3) is not a constant expression either.)
All static objects in C have to be initialized at compile time, at least conceptually. The word "conceptually" in this case refers to the fact that, say, address constant expressions may actually be evaluated much later, even at load time. But the point is that once your program starts running any user-level code, all static objects have to have already known pre-evaluated values, as if they were initialized at compile time. For this reason C (as opposed to C++) does not have/does not need the concept of initialization order for static objects and cannot possibly suffer from SIOF.
So, there's no way around this restriction in standard C. You will not be able to initialize a static object with something that requires (or in any way involves) running code at run-time. Your implementation might provide implementation-specific features that might be able to do something like that, but this is way outside the realm of C language itself.
I'm just wondering whether sentences like const int N=10 will be executed at compilation time. The reason I'm asking is because that the following code will work.
int main()
{
const int N=10;
int a[N]={};
return 0;
}
But this one wouldn't.
int main()
{
int N=10;
int a[N]={};
return 0;
}
The compiler must generate code "as if" the expression was evaluated at
compile time, but the const itself isn't sufficient for this. In
order to be used as the dimension of an array, for example, expression
N must be a "constant integral expression". A const int is
a constant integral expresion only if it is initialized with a constant
integral expression, and the initialization is visible to the compiler.
(Something like extern int const N;, for example, can't be used in
a constant integral expression.)
To be a constant integral expression, however, the variable must be
const; in your second example, the behavior of the compiler and the
resulting program must be "as if" the expression were only evaluated at
runtime (which means that it cannot be used as the dimension of an
array). In practice, at least with optimization, the compiler likely
would evaluate N at compile time, but it still has to pretend it
can't, and refuse to compile the code.
The compiler will probably evaluate both of the examples you provided at compile time, since even though the int N = 10; isn't const, you're not changing it anywhere and you're only assigning a constant value to it, which means the compiler can optimize this.
I recommend you take a look at the constexpr keyword introduced in C++11, which is exactly about being able to evaluate things at compile time.
Compilers will resolve const variables to literals at compile time (and also const expressions, see constant folding). The reason that the first method works is that compiler knows how much space to allocate (10*sizeof(int)) to a in the first method. In the second method the value of N is not known at compile time, and as such there is no way for the compiler to know how much space to allocate for a. Hope that helps.
This sort of thing is an implementation detail that technically is up to the compiler to choose. It could be different on different platforms.
In practice, with the most common compilers:
const int sometimes is and sometimes isn't baked at compile time. For example, the compiler clearly can't hardcode the value of a below into the object file:
int foo( int x )
{
const int a = x+ 1;
return a * 2;
}
In that function, const means it is only constant within the scope of foo(), but it is still a local stack variable.
On the other hand, const int x = 5 seems to be a literal that is usually resolved at compile time by GCC and MSVC (except sometimes they don't turn it into a literal for reasons unclear). I've seen some other compilers that won't turn it into a literal, and always put const int on the stack like an ordinary local variable.
const static int is different, because its scope is static, which means it outlives the function it is declared in, which means it will never change over the life of the program. Every compiler I've ever worked with has turned const static primitives into compile-time literals.
Objects with constructors, however, will still need to be initialized at runtime; so
class Foo {
Foo() : { CallGlobalFunction(); }
};
const static Foo g_whatever;
cannot be optimized into a literal by the compiler.
I understand that the keyword explicit can be used to prevent implicit conversion.
For example
Foo {
public:
explicit Foo(int i) {}
}
My question is, under what condition, implicit conversion should be prohibited? Why implicit conversion is harmful?
Use explicit when you would prefer a compiling error.
explicit is only applicable when there is one parameter in your constructor (or many where the first is the only one without a default value).
You would want to use the explicit keyword anytime that the programmer may construct an object by mistake, thinking it may do something it is not actually doing.
Here's an example:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
With the following code you are allowed to do this:
int age = 29;
//...
//Lots of code
//...
//Pretend at this point the programmer forgot the type of x and thought string
str s = x;
But the caller probably meant to store "3" inside the MyString variable and not 3. It is better to get a compiling error so the user can call itoa or some other conversion function on the x variable first.
The new code that will produce a compiling error for the above code:
class MyString
{
public:
explicit MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
Compiling errors are always better than bugs because they are immediately visible for you to correct.
It introduces unexpected temporaries:
struct Bar
{
Bar(); // default constructor
Bar( int ); // value constructor with implicit conversion
};
void func( const Bar& );
Bar b;
b = 1; // expands to b.operator=( Bar( 1 ));
func( 10 ); // expands to func( Bar( 10 ));
A real world example:
class VersionNumber
{
public:
VersionNumber(int major, int minor, int patch = 0, char letter = '\0') : mMajor(major), mMinor(minor), mPatch(patch), mLetter(letter) {}
explicit VersionNumber(uint32 encoded_version) { memcpy(&mLetter, &encoded_version, 4); }
uint32 Encode() const { int ret; memcpy(&ret, &mLetter, 4); return ret; }
protected:
char mLetter;
uint8 mPatch;
uint8 mMinor;
uint8 mMajor;
};
VersionNumber v = 10; would almost certainly be an error, so the explicit keyword requires the programmer to type VersionNumber v(10); and - if he or she is using a decent IDE - they will notice through the IntelliSense popup that it wants an encoded_version.
Mostly implicit conversion is a problem when it allows code to compile (and probably do something strange) in a situation where you did something you didn't intend, and would rather the code didn't compile, but instead some conversion allows the code to compile and do something strange.
For example, iostreams have a conversion to void *. If you're bit tired and type in something like: std::cout << std::cout; it will actually compile -- and produce some worthless result -- typically something like an 8 or 16 digit hexadecimal number (8 digits on a 32-bit system, 16 digits on a 64-bit system).
At the same time, I feel obliged to point out that a lot of people seem to have gotten an almost reflexive aversion to implicit conversions of any kind. There are classes for which implicit conversions make sense. A proxy class, for example, allows conversion to one other specific type. Conversion to that type is never unexpected for a proxy, because it's just a proxy -- i.e. it's something you can (and should) think of as completely equivalent to the type for which it's a proxy -- except of course that to do any good, it has to implement some special behavior for some sort of specific situation.
For example, years ago I wrote a bounded<T> class that represents an (integer) type that always remains within a specified range. Other that refusing to be assigned a value outside the specified range, it acts exactly like the underlying intger type. It does that (largely) by providing an implicit conversion to int. Just about anything you do with it, it'll act like an int. Essentially the only exception is when you assign a value to it -- then it'll throw an exception if the value is out of range.
It's not harmful for the experienced. May be harmful for beginner or a fresher debugging other's code.
"Harmful" is a strong statement. "Not something to be used without thought" is a good one. Much of C++ is that way (though some could argue some parts of C++ are harmful...)
Anyway, the worst part of implicit conversion is that not only can it happen when you don't expect it, but unless I'm mistaken, it can chain... as long as an implicit conversion path exists between type Foo and type Bar, the compiler will find it, and convert along that path - which may have many side effects that you didn't expect.
If the only thing it gains you is not having to type a few characters, it's just not worth it. Being explicit means you know what is actually happening and won't get bit.
To expand Brian's answer, consider you have this:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
// ...
};
This actually allows this code to compile:
MyString mystr;
// ...
if (mystr == 5)
// ... do something
The compiler doesn't have an operator== to compare MyString to an int, but it knows how to make a MyString out of an int, so it looks at the if statement like this:
if (mystr == MyString(5))
That's very misleading since it looks like it's comparing the string to a number. In fact this type of comparison is probably never useful, assuming the MyString(int) constructor creates an empty string. If you mark the constructor as explicit, this type of conversion is disabled. So be careful with implicit conversions - be aware of all the types of statements that it will allow.
I use explicit as my default choice for converting (single parameter or equivalent) constructors. I'd rather have the compiler tell me immediately when I'm converting between one class and another and make the decision at that point if the conversion is appropriate or instead change my design or implementation to remove the need for the conversion completely.
Harmful is a slightly strong word for implicit conversions. It's harmful not so much for the initial implementation, but for maintenance of applications. Implicit conversions allow the compiler to silently change types, especially in parameters to yet another function call - for example automatically converting an int into some other object type. If you accidentally pass an int into that parameter the compiler will "helpfully" silently create the temporary for you, leaving you perplexed when things don't work right. Sure we can all say "oh, I'll never make that mistake", but it only takes one time debugging for hours before one starts thinking maybe having the compiler tell you about those conversions is a good idea.