Есть ли какой-нибудь трюк ниндзя, чтобы сделать переменную постоянной после ее объявления? - PullRequest
46 голосов
/ 08 сентября 2010

Я знаю, что ответ 99,99% нет, но я подумал, что стоит попробовать, вы никогда не знаете.

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.
}

Я могу сделать что-то похожее с const int b = a;, но это не совсем то же самое, и это создает много путаницы. Допустимо только C ++ 0x-решение.

РЕДАКТИРОВАТЬ : еще один менее отвлеченный пример, который заставил меня задать этот вопрос:

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

РЕДАКТИРОВАТЬ : другой конкретный пример: Постоянство повторного захвата переменных в параллельном сечении .

Ответы [ 8 ]

46 голосов
/ 08 сентября 2010

Вы можете переместить код для генерации a в другую функцию:

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

В противном случае, нет хорошего способа сделать это во время компиляции.

38 голосов
/ 08 сентября 2010

Одним из решений было бы преобразование всего кода мутации в лямбда-выражение.Сделайте всю мутацию в лямбда-выражении и присвойте результат const int в области видимости метода.Например

void SomeFunction(const int p1) { 
  auto calcA = [&]() {
    int a = p1;
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    ..
    return a;
  };
  const int a = calcA();
  ...
}
11 голосов
/ 08 сентября 2010

Шаблон, который я использовал, это «скрыть» аргумент с _, поэтому код становится

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.
}

Вы также можете использовать только переменные const и создать функцию для вычисления нового значенияа, если необходимо.Я все больше склоняюсь к тому, чтобы не «повторно использовать» переменные, и сделать как можно больше моих переменных неизменными: если вы измените значение чего-либо, тогда дайте ему новое имя.

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

}
10 голосов
/ 08 сентября 2010

Почему бы не преобразовать ваш код в две отдельные функции. Тот, который возвращает измененный a, и другой, который работает с этим значением (даже не меняя его).

Вы могли бы также обернуть свой объект вокруг объекта класса держателя и работать с этим держателем.

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
}

Ваш пример легко исправить: рефакторинг.

// 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&
5 голосов
/ 08 сентября 2010

это может быть один из способов сделать это, если вы просто пытаетесь избежать другого имени.Я предлагаю вам подумать дважды, прежде чем использовать это.

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
}
4 голосов
/ 08 сентября 2010

На самом деле я не советую делать это, но вы можете использовать креативные переменные тени, чтобы имитировать что-то вроде того, что вы хотите:

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.
    }
}
0 голосов
/ 11 января 2019

Ответы были довольно солидными, но, честно говоря, я не могу придумать ХОРОШУЮ ситуацию, чтобы использовать это. Однако, если вы хотите предварительно вычислить константу, которая, в основном, и делается, у вас есть несколько основных способов Вы можете сделать это.

Сначала мы можем сделать следующее. Таким образом, компилятор просто установит CompileA # для нас, в данном случае это 50, 100 и 150.

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

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

Теперь, кроме этого, есть так много способов справиться с этим. Мне понравилось предложение, как кто-то еще упомянул о выполнении.

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

Но другой путь мог бы быть ...

SomeFunc(EarlcCalc(a));

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

Или даже ..

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

void ActualFunction(const int A)
{
    //We can't edit A.
}
0 голосов
/ 08 сентября 2010

Конечно, нет способа сделать это, используя то же имя переменной в C ++.

...