Подтвердить что ты не робот

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

Я знаю, что ответ на 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;, но это не совсем то же самое, и это создает много путаницы. Решение С++ 0x приемлемо.

EDIT: еще один менее абстрактный пример, который заставил меня задать этот вопрос:

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

EDIT: еще один конкретный пример: Восстановить константу переменных в параллельном разделе.

4b9b3361

Ответ 1

Одним из решений было бы включить весь код мутации в выражение лямбда. Сделайте всю мутацию в выражении лямбда и присвойте результат в 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();
  ...
}

Ответ 2

Вы можете переместить код, чтобы сгенерировать 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);
  // ....
}

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

Ответ 3

Образец, который я использовал, - это "скрыть" аргумент с помощью _, поэтому код становится

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

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

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

}

Ответ 4

Почему бы не преобразовать ваш код в две отдельные функции. Один, который возвращает измененный 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

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

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
}

Ответ 6

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

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

Ответ 7

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

Сначала мы можем сделать следующее. Таким образом, компилятор просто установит 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.
}

Ответ 8

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