Is There Some Ninja Trick to Make a Variable Constant After Its Declaration

Is there some ninja trick to make a variable constant after its declaration?

One solution would be to factor all of the mutation code into a lambda expression. Do all of the mutation in the lambda expression and assign the result out to a const int in the method scope. For example

void SomeFunction(const int p1) { 
auto calcA = [&]() {
int a = p1;
a *= 50;
a %= 10;
if(example())
a = 0;
..
return a;
};
const int a = calcA();
...
}

or even

void SomeFunction(const int p1) { 
const int a = [&]() {
int a = p1;
a *= 50;
a %= 10;
if(example())
a = 0;
..
return a;
}();
...
}

Is there a way to constify of a variable after declaring it?

Yes.

Put the initialization in a function.

int getInitCValue(int const& someVar)
{
// the value of c is initialized here
switch(someVar)
{
case foo: return 3;
case bar: return 4;
default : return 42; // what else?
}
}

int const c = getInitCValue(someVar);

Edit: To answer the modified question.

You want to initialize two values:

std::pair<int,int> const value = initalizePairOfValues(someValue);
int const& c = value.first;
int const& d = value.second;

Edit 2: Go with Péter Török deleted solution (Peter if you un-delete I will remove this).

struct ConstValues
{
ConstValues()
{
switch(....)
// Initialize C/D
}
int const& getC() const {return c;}
int const& getD() const {return d;}
private:
int c;
int d;
};

Adding const-ness after the fact in C++

What about:

string MakeData(string const&)
{
...
return string(...); // for return value optimization
}

followed by

int main()
{
string const& str = MakeData("Something that makes sense to humans");
}

The difference with what you do is using a const reference, and only one function. If you cannot change MutateData, do what you suggested (with the const reference though)

Constants in C: declaration separate from definition

Semantically the first example means "a pointer to a const int" not "a const pointer to an int".

So, when you set i to point to j (a non-const int). i now points to a const, as such you can't change the value of j through the pointer i, for example:

int main()
{
const int *i;
int j=2;

i=&j;

*i = 4;
}

Won't compile, giving the error "assignment of read-only location ‘*i’". So the pointer restricts your access to the value being pointed to. But the pointer itself can still be changed.

C being the language that it is, doesn't really offer much protection and you can often throw away the const and assign the variable a new value anyway e.g.:

#include <stdio.h>

void assign(int *a) {
*a=5;
}

int main()
{
int const i=1;
int j=2;
assign((int *) &i);
printf("i: %d\n",i);
}

But I'm not sure I'd recommend it. And while this works in some versions of gcc, this behavior is likely undefined in the C standard.

How can I make a variable always equal to the result of some calculations?

Edit: While I fully answered the question as asked, please have a look at Artelius' answer, too. It addresses some issues my answer doesn't (encapsulation, avoidance of redundancies, risks of dangling references). A possible optimisation, if calculation is expensive, is shown in Jonathan Mee's answer.


You mean something like this:

class Z
{
int& x;
int& y;
public:
Z(int& x, int& y) : x(x), y(y) { }
operator int() { return x + y; }
};

The class delays calculation of the result until casted as int. As cast operator is not explicit, Z can be used whenever an int is required. As there's an overload of operator<< for int, you can use it with e. g. std::cout directly:

int x, y;
Z z(x, y);
std::cin >> x >> y;
if(std::cin) // otherwise, IO error! (e. g. bad user input)
std::cout << z << std::endl;

Be aware, though, that there's still a function call (the implicit one of the cast operator), even though it is not visible. And actually the operator does some true calculations (rather than just accessing an internal member), so it is questionable if hiding away the function call really is a good idea...

Would it make sense to have a 'constify' operation in C++?

Frankly, I find it less confusing if a variable is either const or not, than if this can change.


To elaborate a bit on this: The reason you usually want to do this is because you cannot initialize a const variable the way you want to. std::vector is a good example of this. Well, for once, the next standard introduces a universal initialization syntax that makes this possible:

const std::vector<int> cvi = { 1, 2, 3, 4, 5, 42 }; 

However, even without C++1x' stuff at hand, and even with types that disallow this initialization syntax, you can always create a helper function to do what you want:

const std::vector<int>& cvi = create_my_vector();

or, if you want to be fancy:

const std::vector<int>& cvi = compile_time_list<1,2,3,4,5,42>::create_vector();

Note the &. There's no point in copying the result of the function call, since binding an rvalue to a const reference extends its lifetime until the end of the reference's lifetime.

Of course, recompiling with a compiler that supports C++1x' move semantics will render such optimizations pretty much needless. But binding an rvlaue to a const reference might still be faster than moving a vector and is unlikely to be slower.

With C++1x, you might also create lambda functions doing this one the fly. C++ just provides an incredibly huge arsenal of tools. IME, no matter how hard you have thought, someone else ought to come up with yet another idea to do the same thing. And often a better one than yours.


However, IME this problem usually only comes with too much code in too few functions anyway. And then it doesn't only apply to constness, but also to similar traits - like what a reference refers to.

A classic is the use-one-of-several-possible-streams. Instead of this

int main(int argc, char* argv[])
{
std::istream* istrm = NULL;
std::ifstream ifs;
if( argc > 1 )
{
ifs.open( argv[1] );
if( ifs.good() )
istrm = &ifs;
}
if( !istrm )
istrm = &std::cin;

while( istrm->good() )
{
// reading from *istrm implemented here
}
return 0;
}

just split the concerns into 1) figuring out where to read from and 2) the actual reading:

int read(std::istream& is)
{
while( is.good() )
{
// reading from is implemented here
}
return 0;
}

int main(int argc, char* argv[])
{
if( argc > 1 )
{
std::ifstream ifs( argv[1] );
if( ifs.good() )
return read(ifs);
}
return read(std::cin);
}

I have yet to see a real-world example of a variable that wasn't as constant as it could have been which couldn't be fixed by separating of concerns.

Is there a way I can keep something at a constant speed in C++ game?

Bascially, to move something at a constant rate, you want to base the distance moved based on the elapsed time since you previously moved that object, not the elapsed time since the beginning of the current cycle, like you are doing here.

So your move function should be something like:

void Enemy::move(float height, float width, Player player) {
std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
// various code that moves by enemy_speed * (now - prev_time)
prev_time = now;
}

where prev_time is a field in the enemy object where you store the previous timestamp of movement. You need to make sure you initialize it to an inital time properly, or the first move will "jump" unexpectedly.

You can reduce the number of times you query the clock by having a single timestamp for all the enemies/objects and passing in the elapsed time since the previous timestamp to all the move routines.

constant variable declaration in Haskell

Untagged constants are bad. If you go with bunch of Int constants then you lose type-checking (think about possible values that Int -> whatever function takes as opposed to SomeConstType -> whatever) and possibly introduce bugs. You want a strong type instead:

data Colour = Red | Blue | Green deriving (Show, Eq, Enum)

Also, representing those values as integers is not really necessary in most cases. If you actually do need it, Enum typeclass provides toEnum and fromEnum.

As for namespaces: modules are namespaces in Haskell. Put your type in a module and then you can import it qualified and you'll have your prefix:

-- Colours.hs
module Colours (Colour) where
data Colour = ...

-- SomeOtherModule.hs
module SomeOtherModule where
import qualified Colours

foo = Colours.Red

That said, creating modules just for this one type with constants (or importing them qualified) is not really necessary, because you can easily trace things by their types.



Related Topics



Leave a reply



Submit