Есть ли какой-нибудь трюк ниндзя, чтобы сделать переменную константой после ее объявления?
Я знаю, что ответ на 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: еще один конкретный пример: Восстановить константу переменных в параллельном разделе.
Ответы
Ответ 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
Конечно, нет способа сделать это, используя одно и то же имя переменной в С++.