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

C++C++11Const Correctness

C++ Problem Overview


I know the answer is 99.99% no, but I figured it was worth a try, you never know.

void SomeFunction(int a)
{
    // Here some processing happens on a, for example:
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    // From this point on I want to make "a" const; I don't want to allow
    // any code past this comment to modify it in any way.
}

I can do something somewhat similar with const int b = a;, but it's not really the same and it creates a lot of confusion. A C++0x-only solution is acceptable.

EDIT: another less abstracted example, the one that made me ask this question:

void OpenFile(string path)
{
    boost::to_lower(path);
    // I want path to be constant now
    ifstream ...
}

EDIT: another concrete example: Recapture const-ness on variables in a parallel section.

C++ Solutions


Solution 1 - C++

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;
  }();
  ...
}

Solution 2 - C++

You could move the code to generate a into another function:

int ComputeA(int a) {
  a *= 50;
  a %= 10;
  if (example())
    a = 0;
  return a;
}

void SomeFunction(const int a_in) {
  const int a = ComputeA(a_in);
  // ....
}

Otherwise, there's no nice way to do this at compile time.

Solution 3 - C++

A pattern I used to use is to "hide" the argument with an _, so the code becomes

void SomeFunction(int _a)
{
    // Here some processing happens on a, for example:
    _a *= 50;
    _a %= 10;
    if(example())
       _a = 0;

    const int a = _a;
    // From this point on I want to make "a" const; I don't want to allow
    // any code past this comment to modify it in any way.
}

You could also use only const variables and make a function to compute the new value of a, if necessary. I tend more en more to not "reuse" variables en make as much as possible my variables immutable : if you change the value of something , then give it a new name.

void SomeFunction(const int _a)
{
    const int a = preprocess(_a);
    ....
   
}

Solution 4 - C++

Why not refactor your code in to two separate functions. One that returns a modified a and another that works on this value (without ever changing it).

You could possibly wrap your object too around a holder class object and work with this holder.

template <class T>
struct Constify {
    Constify(T val) : v_( val ) {}
    const T& get() const  { return v_; }
};

void SomeFuncion() {
    Constify ci( Compute() ); // Compute returns `a`
    // process with ci
}

Your example has an easy fix: Refactoring.

// expect a lowercase path or use a case insensitive comparator for basic_string
void OpenFile(string const& path)  
{        
    // I want path to be constant now
    ifstream ...
}

OpenFile( boost::to_lower(path) ); // temporaries can bind to const&

Solution 5 - C++

I don't actually suggest doing this, but you could use creative variable shadowing to simulate something like what you want:

void SomeFunction(int a)
{
    // Here some processing happens on a, for example:
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    {
        const int b = a;
        const int a = b;  // New a, shadows the outside one.
        // Do whatever you want inside these nested braces, "a" is now const.
    }
}

Solution 6 - C++

this might be one way to do it, if you are just trying to avoid another name. i suggest you think twice before using this.

int func ()
{
    int a;
    a %= 10;

const int const_a = a;
#define a const_a

    a = 10;  // this will cause an error, as needed.
#undef a
}

Solution 7 - C++

Answers were pretty solid, but honestly I can't really think of a GOOD situation to use this in. However in the event you want to Pre-Calculate a constant which is basically what you are doing you have a few main ways You can do this.

First we can do the following. So the compiler will simply set CompileA# for us in this case it's 50, 100, and 150.

const int CompileA1 = EarlyCalc(1);
const int CompileA2 = EarlyCalc(2);
const int CompileA3 = EarlyCalc(3);

int EarlyCalc(int a)
{
	a *= 50;
	return a;
}

Now anything beyond that there's so many ways you can handle this. I liked the suggestion as someone else had mentioned of doing.

void SomeFunc(int a)
{
	const int A = EarlyCalc(a);
	//We Can't edit A.
}

But another way could be...

SomeFunc(EarlcCalc(a));

void SomeFunc(const int A)
{
	//We can't edit A.
}

Or even..

SomeFunction(int a)
{
    a *= 50;
    ActualFunction(a);
}

void ActualFunction(const int A)
{
	//We can't edit A.
}

Solution 8 - C++

Sure, there is no way to do it using the same variable name in C++.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThomas BoniniView Question on Stackoverflow
Solution 1 - C++JaredParView Answer on Stackoverflow
Solution 2 - C++bdonlanView Answer on Stackoverflow
Solution 3 - C++mb14View Answer on Stackoverflow
Solution 4 - C++dirkgentlyView Answer on Stackoverflow
Solution 5 - C++Mark BView Answer on Stackoverflow
Solution 6 - C++alvinView Answer on Stackoverflow
Solution 7 - C++Jeremy TrifiloView Answer on Stackoverflow
Solution 8 - C++OlegView Answer on Stackoverflow