views:

299

answers:

6

I'm trying to declare a variable in an if-else block as follows:

int main(int argc, char *argv[]) {

    if (argv[3] == string("simple")) {
        Player & player = *get_Simple();
    } else if (argv[3] == string("counting")) {
        Player & player = *get_Counting();
    } else if (argv[3] == string("competitor")) {
        Player & player = *get_Competitor();
    }

    // More code
}

But, I'm getting the following errors when I try to compile:

driver.cpp:38: error: unused variable ‘player’
driver.cpp:40: error: unused variable ‘player’
driver.cpp:42: error: unused variable ‘player’
driver.cpp:45: error: ‘player’ was not declared in this scope

Any ideas?

+3  A: 

If you put a static variable inside of a scope, delimited by { }, then that variable will no longer be available when the scope ends.

Try this instead:

int main(int argc, char *argv[]) {

    // TODO: validate argc and argv here
    if (argc < 3) {
        printf("error: not enough arguments\n");
        exit(1);
    }

    Player* player_ptr = NULL;
    if (argv[3] == string("simple")) {
        player_ptr = get_Simple();
    } else if (argv[3] == string("counting")) {
        player_ptr = get_Counting();
    } else if (argv[3] == string("competitor")) {
        player_ptr = get_Competitor();
    }

    if (!player_ptr) {
        printf("error: invalid argument %s\n", argv[3]);
        exit(1);
    }

    Player& player = *player_ptr;

    // More code
}
Parappa
A reference must have an initial value.
Jim Buck
Will this compile? references must be initialized ...
stefanB
Yup, I messed up. Tried to fix it.
Parappa
You also need to NULL the pointer, otherwise the assert might be completely off, since it might skip all of the clauses. And in the same spirit, since the pointer can remain NULL, referencing might be a problem.
laura
And, of course, you should not use assertions to validate user inputs
erikkallen
A: 

In

if (argv[3] == string("simple")) {
    Player & player = *get_Simple();
}

The variable only exists between the {}'s. When you get to the }, the variable has not been used and will be discarded, never having been used.

S.Lott
+12  A: 

Your problem is that player falls out of scope in each if / else if block.

You need to declare your variable above all of the if statements.

But you can't use a reference for that because you must initialize a reference right away.

Instead you probably want something like this:

int main(int argc, char *argv[]) {

    Player * pPlayer = NULL;
    if (argv[3] == string("simple")) {
        pPlayer = get_Simple();
    } else if (argv[3] == string("counting")) {
        pPlayer = get_Counting();
    } else if (argv[3] == string("competitor")) {
        pPlayer = get_Competitor();
    }

    //Then if you really want to...
    Player &player = *pPlayer;

}
Brian R. Bondy
This advice is sound, but I'd suggest that you could avoid the whole pointer/reference switcheroo at the end by having a factory method that takes your type parameter and returns a `Player*`. So your main method becomes `Player `, and the `if` statements in `getPlayerByType()` each return directly, thus avoiding all that local variable ugliness.
bradheintz
@bradheintz: That advice does not help in the slightest (in-fact it clutters up the answer by providing spurious advice). It is obvious that the OP is actually trying to do exactly what you say (and return a reference (rather than a pointer as in your solution)). But has posted the simplist compilable version of the question here. If you want to post an answer do that, then we can at least give you a negative mark for not answering the question.
Martin York
I'm not sure what's spurious about packaging the object creation into a single-responsibility function, eliminating an unnecessary local variable, and making the main() function more scannable - but if it makes you happier to call my advice "spurious", or to call a suggested refinement of Brian R. Bondy's good advice "cluttering" without supporting the assertion, go for it.
bradheintz
+1  A: 

You've declared three separate player variables in three different scopes, and the error message is saying exactly what it means.

You need to declare a single player variable outside the if-statement and assign the result. This is tricky, since player is a reference--you must initialize it once.

You can put the if-statement in a function (say GetPlayer()) that returns a pointer to the object, and then initialize player with *GetPlayer().

Adrian McCarthy
+6  A: 

Others have suggested pointers. However, the conditional operator may be used as well.

Player & player = argv[3] == string("simple") ? get_Simple()
                : argv[3] == string("counting") ? get_Counting() 
                : get_Competitor();
rlbond
A: 
#include <map>

int main(int argc, char **argv)
{
    typedef std::map<std::string, Player*(*)()> lookup;
    lookup mapping;

    mapping["simple"] = get_Simple;
    mapping["counting"] = get_Counting;
    mapping["competitor"] = get_Competitor;

    lookup::const_iterator it = mapping.find(argv[3]);
    if (it == mapping.end())
    {
        std::cout << "illegal argument\n";
    }
    else
    {
        Player& player = *it->second();
        // more code
    }
}
Fred