3

Please assume the version of gcc 7.2.1 in this question

I would like to declare a global variable which behave like a const however, the value to initialize it cannot not be detected before the program being executed. In other words, the target variable would be re-assigned since the first time it is assigned.

An ugly approach of this concept as follow:

#include<iostream>

int numberOfPeople; //Do not re-assign it after it first assign

int main(){
  std::cin >> numberOfPeople; // Do not re-assign numberOfPeople since then !!!
  // Following of codes omitted.
}

As you could see, this is a very ugly approach and cannot be checked by compiler. I wonder whether there is a kind of notation in c++ that can freeze the variable since it first assigned.

So I can write code like this:

#include<iostream>

magic_notation int numberOfPeople;

int main(){
  std::cin >> numberOfPeople; // Allowed as it's first assign.
  // Median codes omitted.
  numberOfPeople = 60. //Disallowed and will get an error message from compiler!
  // Following codes omitted.
}

Is there any kind of notation as can use like the magic_notation in the code above in c++?

TJM
  • 709
  • 1
  • 6
  • 11
  • Make it a member of a class that controls access. –  Dec 22 '17 at 22:42
  • @neil-butterworth Thanks for your reply. However, could you please give me an example code? – TJM Dec 22 '17 at 22:44
  • I think you are looking for this: https://stackoverflow.com/questions/35800643/is-it-possible-to-define-a-variable-that-can-be-set-only-once – Eljay Dec 22 '17 at 22:45
  • @EIjay Thanks for your reply. It's similar. However, I would like to find a syntax based solution. – TJM Dec 22 '17 at 22:48
  • 1
    @TJM • I don't think you'd be able to get a compile time error as you had requested. It could just silently ignore subsequent assignments, or throw an exception on subsequent assignments. – Eljay Dec 22 '17 at 22:49
  • When I want some behaviour like this, rather than using globals, I usually find that what I really want is to initialize my configuration in main, then pass the configuration options around (as `const`). – Justin Dec 22 '17 at 22:58
  • @Justin Yes, singleton or just passing const arguments works for this question. However, I'm just curious about whether there is a syntactic sugar for this situation. – TJM Dec 22 '17 at 23:01

3 Answers3

1

The best approach is to make a class with a public const member variable which gets initialized in the constructor:

struct InitInfo {
    const int numberOfPeople;
    InitInfo() numberOfPeople(getNumberOfPeople()) {
    }
private:
    static int getNumberOfPeople() {
        int res;
        cin >> res;
        return res;
    }
};
InitInfo initInfo;

Now you can use the member variable as follows:

int main() {
    cout << initInfo.numberOfPeople << endl;
}

You can use the same approach for initializing a global variable, too.

static int getNumberOfPeople() {
    int res;
    cin >> res;
    return res;
}
const int numberOfPeople = getNumberOfPeople();
int main() {
    cout << numberOfPeople << endl;
    numberOfPeople += 10; // <<== This triggers an error
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
0

One approach you can use is to wrap the variable as a static variable in a function. Use the function instead of the variable in rest of your code.

#include <iostream>

int readFromStdin()
{
   int n;
   cin >> n;
   return n;
}

// Wrap it arund in a function.
// int numberOfPeople; //Do not re-assign it after it first assign

int getNumberOfPeople()
{
   // Initialize by reading from stdin.
   static int numberOfPeople = readFromStdin();
   returnn numberOfPeople;
}

int main(){

   // Use the function instead of the variable.
   getNumberOfPeople();
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Thanks for your reply, it looks like singleton pattern. However, is there any simpler way to do this? – TJM Dec 22 '17 at 22:50
  • @TJM No there is not. There isn't a modifier like `const` which you can simply add to your variable declaration. Perhaps you can find a library that provides a `write_once` class template or something, so you can write `write_once numberOfPeople;` and it would work like you intent. – Justin Dec 22 '17 at 22:51
  • @Justin ...well, technically there is: you _could_ just cast away the const-ness at assignment. Cringe-worthy, I know. – Dúthomhas Dec 22 '17 at 22:54
  • 2
    @Dúthomhas, that would be undefined behavior from the get go. – R Sahu Dec 22 '17 at 22:55
  • Er, _writing_ to const stuff is undefined behavior IFF we don’t know anything more about the data than its const-on-arrival. OP is asking about data specifically known to be non-const but presented to all as const. It is a fine hair to split, I agree, and again I don’t really recommend it. – Dúthomhas Dec 22 '17 at 23:51
0

In case you have different ways to initialize the variable, you could come up with something like this:

struct {
    int value() const { return _val; }
    void init(int val) {
        if(!_set) _val = val;
    }
  private:
    int _val;
    bool _set = false;
} numberOfPeople;

Now, everybody who uses the variable should call init before using it to make sure it is initialized.

steiny
  • 203
  • 3
  • 9