web-dev-qa-db-fra.com

Y at-il un truc de ninja pour faire une constante de variable après sa déclaration?

Je sais que la réponse est 99,99% non, mais je me suis dit que ça valait la peine d'essayer, on ne sait jamais.

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

Je peux faire quelque chose de similaire avec const int b = a;, mais ce n'est pas vraiment pareil et cela crée beaucoup de confusion. Une solution C++ 0x uniquement est acceptable.

EDIT: un autre exemple moins abstrait, celui qui m'a fait poser cette question:

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

EDIT: un autre exemple concret: Recapture const-ness sur des variables d'une section parallèle .

44
Andreas Bonini

Une solution serait de factoriser tout le code de mutation dans une expression lambda. Effectuez toute la mutation dans l'expression lambda et affectez le résultat à un const int dans la portée de la méthode. Par exemple

void SomeFunction(const int p1) { 
  auto calcA = [&]() {
    int a = p1;
    a *= 50;
    a %= 10;
    if(example())
       a = 0;
    ..
    return a;
  };
  const int a = calcA();
  ...
}
36
JaredPar

Vous pouvez déplacer le code pour générer a dans une autre fonction:

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

Sinon, il n'y a pas de moyen agréable de le faire au moment de la compilation.

46
bdonlan

Un motif que j’utilisais auparavant est de "cacher" l’argument avec un _, le code devient alors

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

Vous pouvez également utiliser uniquement des variables const et créer une fonction pour calculer la nouvelle valeur de a, si nécessaire. J'ai plutôt tendance à ne pas "réutiliser" les variables et à rendre autant que possible mes variables immuables: si vous modifiez la valeur de quelque chose, donnez-lui un nouveau nom. 

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

}
11
mb14

Pourquoi ne pas refactoriser votre code en deux fonctions distinctes. Un qui retourne une a modifiée et un autre qui fonctionne avec cette valeur (sans jamais la changer).

Vous pouvez éventuellement envelopper votre objet aussi autour d'un objet de classe de titulaire et travailler avec ce titulaire.

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
}

Votre exemple présente une solution simple: le 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&
10
dirkgently

cela pourrait être une façon de le faire, si vous essayez simplement d'éviter un autre nom. Je vous suggère de réfléchir à deux fois avant de l'utiliser.

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
}
5
alvin

En fait, je ne suggère pas de faire cela, mais vous pouvez utiliser une création créative d'ombrage pour simuler quelque chose du genre:

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.
    }
}
4
Mark B

Les réponses étaient assez solides, mais honnêtement, je ne peux vraiment pas penser à une bonne situation pour l'utiliser. Toutefois, si vous souhaitez pré-calculer une constante qui correspond essentiellement à ce que vous faites, vous pouvez procéder de différentes manières. ce.

Tout d'abord, nous pouvons faire ce qui suit. Ainsi, le compilateur définira simplement CompileA # pour nous, dans ce cas, 50, 100 et 150.

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

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

Maintenant, tout ce qui va au-delà de cela vous permet de gérer cela de nombreuses façons. J'ai aimé la suggestion comme quelqu'un d'autre l'avait mentionné. 

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

Mais une autre façon pourrait être ...

SomeFunc(EarlcCalc(a));

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

Ou même..

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

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