'*' cannot appear in a constant-expression problem

Discussion in 'C++' started by Stefano Sabatini, Oct 24, 2008.

  1. Hi all, I'm encountering this while trying to implement a factory
    singleton method to generate objects.

    The singleton has a static map which binds a static creation function
    defined in each class to the type of the object to be created.

    Here it is the code, which is a modification of the wikipedia C++
    factory example code:

    ----------------------------------8<--------------------------------
    #include <string>
    #include <iostream>
    #include <map>

    class Pizza {
    public:
    virtual void get_price() = 0;
    };

    class HamAndMushroomPizza: public Pizza {
    public:
    virtual void get_price(){
    std::cout << "Ham and Mushroom: $8.5" << std::endl;
    }

    static Pizza* create_pizza()
    {
    return new HamAndMushroomPizza;
    }
    };

    class DeluxePizza : public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Deluxe: $10.5" << std::endl;
    }

    static Pizza* create_pizza()
    {
    return new DeluxePizza;
    }

    };

    class SeafoodPizza : public Pizza {
    public:
    virtual void get_price(){
    std::cout << "Seafood: $11.5" << std::endl;
    }

    static Pizza* create_pizza()
    {
    return new SeafoodPizza;
    }
    };

    class PizzaFactory {
    private:

    static std::map<std::string, (Pizza *)(*)()> creators;

    init() {
    map["Deluxe"] = DeluxPizza::create_pizza;
    map["Ham and Mushroom"] = HamAndMushroom::create_pizza;
    map["Seafood"] = SeafoodPizza::create_pizza;
    }

    public:
    PizzaFactory* get_instance()
    {
    static PizzaFactory instance = 0;
    if (!instance) {
    instance = new PizzaFactory;
    instance.Init();
    }
    return instance;
    }

    static Pizza* create_pizza(const std::string type) {
    PString type = config.GetAttribute("type");
    if ((it = creators.find(type) != creators.end()))
    return (it->second)();
    else
    return 0;
    }
    };

    // usage
    int main() {
    PizzaFactory* factory = PizzaFactory::get_instance();
    Pizza *pizza = 0;

    pizza = factory->create_pizza("Default");
    pizza->get_price();
    delete pizza;

    pizza = factory->create_pizza("Ham and Mushroom");
    pizza->get_price();
    delete pizza;

    pizza = factory->create_pizza("Seafood Pizza");
    pizza->get_price();
    delete pizza;
    }
    ----------------------------------8<--------------------------------

    The static map declaration syntax is somehow wrong, and after hitting
    my head sometime I still can't get out of it.

    I'm using g++ 4.3.1, and the syntax error I get is this:

    make PizzaFactory2; and PizzaFactory2
    g++ -I/home/stefano/opt/reilabs/include -I/home/stefano/include -O0 -g -ggdb PizzaFactory2.cxx -c -o PizzaFactory2.o
    PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    PizzaFactory2.cxx:50: error: template argument 2 is invalid

    The exact line of the error is:
    static std::map<std::string, (Pizza *)(*)()> creators;

    which I interpret as:
    a static map from string to a static method pointer which takes no
    parameters and returns a pointer to a Pizza object.

    What am I missing or what I'm doing wrongly?

    Regards and many help in advance.
     
    Stefano Sabatini, Oct 24, 2008
    #1
    1. Advertising

  2. On 2008-10-24, Stefano Sabatini <> wrote:
    > Hi all, I'm encountering this while trying to implement a factory
    > singleton method to generate objects.
    >
    > The singleton has a static map which binds a static creation function
    > defined in each class to the type of the object to be created.
    >
    > Here it is the code, which is a modification of the wikipedia C++
    > factory example code:
    >
    > ----------------------------------8<--------------------------------

    [...]
    > ----------------------------------8<--------------------------------


    Sorry it had tons of erros, check below the new version.

    > The static map declaration syntax is somehow wrong, and after hitting
    > my head sometime I still can't get out of it.
    >
    > I'm using g++ 4.3.1, and the syntax error I get is this:
    >
    > make PizzaFactory2; and PizzaFactory2
    > g++ -I/home/stefano/opt/reilabs/include -I/home/stefano/include -O0 -g -ggdb PizzaFactory2.cxx -c -o PizzaFactory2.o
    > PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    > PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    > PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    > PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    > PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    > PizzaFactory2.cxx:50: error: template argument 2 is invalid
    >
    > The exact line of the error is:
    > static std::map<std::string, (Pizza *)(*)()> creators;
    >
    > which I interpret as:
    > a static map from string to a static method pointer which takes no
    > parameters and returns a pointer to a Pizza object.
    >
    > What am I missing or what I'm doing wrongly?


    Well I found a solution, even if I'm not sure I really understood it.

    If I define the type like this:
    typedef Pizza *(* pizza_creator_fn_ptr)();

    and then use the map like this:
    static map<std::string, pizza_creator_fn_ptr> creators;

    then it seems to work fine.

    A short explanation would be nice.

    New version here:
    -----------------------------------8<-------------------------------------
    #include <string>
    #include <iostream>
    #include <map>

    class Pizza {
    public:
    virtual void get_price() = 0;
    };

    class HamAndMushroomPizza: public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Ham and Mushroom: $8.5" << std::endl;
    }

    static Pizza* create_pizza() {
    return new HamAndMushroomPizza;
    }
    };

    class DeluxePizza : public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Deluxe: $10.5" << std::endl;
    }

    static Pizza* create_pizza() {
    return new DeluxePizza;
    }
    };

    class SeafoodPizza : public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Seafood: $11.5" << std::endl;
    }

    static Pizza* create_pizza() {
    return new SeafoodPizza;
    }
    };

    typedef Pizza* (*pizza_creator_fn_ptr)(void);

    class PizzaFactory {
    private:
    static std::map<std::string, pizza_creator_fn_ptr> creators;

    void init() {
    creators["Deluxe"] = &DeluxePizza::create_pizza;
    creators["Ham and Mushroom"] = &HamAndMushroomPizza::create_pizza;
    creators["Seafood"] = &SeafoodPizza::create_pizza;
    }

    public:
    static PizzaFactory* get_instance()
    {
    static PizzaFactory * instance = 0;
    if (!instance) {
    instance = new PizzaFactory;
    instance->init();
    }
    return instance;
    }

    static Pizza* create_pizza(const std::string& type) {
    std::map<std::string, pizza_creator_fn_ptr>::iterator it;
    if ((it = creators.find(type)) != creators.end())
    return (*(it->second))();
    else
    return 0;
    }
    };

    //usage
    int main() {
    PizzaFactory* factory = PizzaFactory::get_instance();
    Pizza *pizza = 0;

    pizza = factory->create_pizza("Default");
    pizza->get_price();
    delete pizza;

    pizza = factory->create_pizza("Ham and Mushroom");
    pizza->get_price();
    delete pizza;

    pizza = factory->create_pizza("Seafood Pizza");
    pizza->get_price();
    delete pizza;
    }
    -----------------------------------8<-------------------------------------

    The code has still a problem related to the use of the static map
    which isn't found by the compiler, but this is another problem.

    Thanks for your attention.
     
    Stefano Sabatini, Oct 24, 2008
    #2
    1. Advertising

  3. On 2008-10-24, Pete Becker <> wrote:
    > On 2008-10-24 05:46:59 -0400, Stefano Sabatini
    ><> said:
    >
    > [~90 lines of mostly irrelevant code snipped]
    >
    >>
    >> I'm using g++ 4.3.1, and the syntax error I get is this:
    >>
    >> make PizzaFactory2; and PizzaFactory2
    >> g++ -I/home/stefano/opt/reilabs/include -I/home/stefano/include -O0 -g
    >> -ggdb PizzaFactory2.cxx -c -o PizzaFactory2.o
    >> PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: a function call cannot appear in a
    >> constant-expression
    >> PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: a function call cannot appear in a
    >> constant-expression
    >> PizzaFactory2.cxx:50: error: a function call cannot appear in a
    >> constant-expression
    >> PizzaFactory2.cxx:50: error: template argument 2 is invalid
    >>
    >> The exact line of the error is:
    >> static std::map<std::string, (Pizza *)(*)()> creators;
    >>

    >
    > #include <string>
    > #include <map>
    > class Pizza;
    > std::map<std::string, (Pizza*)(*)()> creators;
    >
    > These four lines produce the same series of error messages. Learn how
    > to reduce code that produces error messages to a minimal example. In
    > the course of doing that, the error usually becomes obvious. If it
    > doesn't become obvious (and this one isn't obvious), post the minimal
    > example. This code compiles cleanly:
    >
    > #include <string>
    > #include <map>
    > class Pizza;
    > std::map<std::string, Pizza*(*)()> creators;


    OK, so the problem was the superfluous parentehsis.

    > In general, though, don't write complicated types on the fly (pointers
    > to functions are complicated types). Use typedefs:
    >
    > typedef Pizza*(*creator)();
    > std::map<std::string, creator> creators;


    Yes, good advice.

    Many thanks, regards.
     
    Stefano Sabatini, Oct 24, 2008
    #3
  4. On 2008-10-24, Stefano Sabatini <> wrote:
    > On 2008-10-24, Stefano Sabatini <> wrote:
    >> Hi all, I'm encountering this while trying to implement a factory
    >> singleton method to generate objects.
    >>
    >> The singleton has a static map which binds a static creation function
    >> defined in each class to the type of the object to be created.
    >>
    >> Here it is the code, which is a modification of the wikipedia C++
    >> factory example code:
    >>
    >> ----------------------------------8<--------------------------------

    > [...]
    >> ----------------------------------8<--------------------------------

    >
    > Sorry it had tons of erros, check below the new version.
    >
    >> The static map declaration syntax is somehow wrong, and after hitting
    >> my head sometime I still can't get out of it.
    >>
    >> I'm using g++ 4.3.1, and the syntax error I get is this:
    >>
    >> make PizzaFactory2; and PizzaFactory2
    >> g++ -I/home/stefano/opt/reilabs/include -I/home/stefano/include -O0 -g -ggdb PizzaFactory2.cxx -c -o PizzaFactory2.o
    >> PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: `*' cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: a function call cannot appear in a constant-expression
    >> PizzaFactory2.cxx:50: error: template argument 2 is invalid
    >>
    >> The exact line of the error is:
    >> static std::map<std::string, (Pizza *)(*)()> creators;
    >>
    >> which I interpret as:
    >> a static map from string to a static method pointer which takes no
    >> parameters and returns a pointer to a Pizza object.
    >>
    >> What am I missing or what I'm doing wrongly?

    >
    > Well I found a solution, even if I'm not sure I really understood it.
    >
    > If I define the type like this:
    > typedef Pizza *(* pizza_creator_fn_ptr)();
    >
    > and then use the map like this:
    > static map<std::string, pizza_creator_fn_ptr> creators;
    >
    > then it seems to work fine.
    >
    > A short explanation would be nice.


    As we discovered the problem was the superfluous parentheses.

    > New version here:
    > -----------------------------------8<-------------------------------------

    [...]
    > -----------------------------------8<-------------------------------------
    >
    > The code has still a problem related to the use of the static map
    > which isn't found by the compiler, but this is another problem.


    For the archive, the problem was due to the (non obvious) fact that a
    static map has to be also defined in the implementation, that is
    outside the delclaration. Adding the missing definition:

    std::map<std::string, pizza_creator_ptr> PizzaFactory::creators;

    fixed the problem.

    Reposting the correct and running version of the toy pizza creator
    singleton/factory sample.

    ----------------------------------------8<------------------------
    #include <string>
    #include <map>
    #include <iostream>

    class Pizza {
    public:
    virtual void get_price() = 0;
    };

    class HamAndMushroomPizza: public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Ham and Mushroom: $8.5" << std::endl;
    }

    static Pizza* create_pizza() {
    return new HamAndMushroomPizza;
    }
    };

    class DeluxePizza : public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Deluxe: $10.5" << std::endl;
    }

    static Pizza* create_pizza() {
    return new DeluxePizza;
    }
    };

    class SeafoodPizza : public Pizza {
    public:
    virtual void get_price() {
    std::cout << "Seafood: $11.5" << std::endl;
    }

    static Pizza* create_pizza() {
    return new SeafoodPizza;
    }
    };

    typedef Pizza* (*pizza_creator_ptr)(void);

    class PizzaFactory {
    private:
    static std::map<std::string, pizza_creator_ptr> creators;

    void init() {
    PizzaFactory::creators["Deluxe"] = &DeluxePizza::create_pizza;
    PizzaFactory::creators["Ham and Mushroom"] = &HamAndMushroomPizza::create_pizza;
    PizzaFactory::creators["Seafood"] = &SeafoodPizza::create_pizza;
    }

    public:
    static PizzaFactory* get_instance()
    {
    static PizzaFactory * instance = 0;
    if (!instance) {
    instance = new PizzaFactory;
    instance->init();
    }
    return instance;
    }

    Pizza* create_pizza(const std::string& type) {
    std::map<std::string, pizza_creator_ptr>::iterator it;
    if ((it = PizzaFactory::creators.find(type)) != creators.end())
    return (*(it->second))();
    else
    return 0;
    }
    };

    std::map<std::string, pizza_creator_ptr> PizzaFactory::creators;

    //usage
    int main() {
    PizzaFactory* factory = PizzaFactory::get_instance();
    Pizza *pizza = 0;

    if (pizza = factory->create_pizza("Default")) {
    pizza->get_price();
    delete pizza;
    }

    if (pizza = factory->create_pizza("Ham and Mushroom")) {
    pizza->get_price();
    delete pizza;
    }

    if (pizza = factory->create_pizza("Seafood")) {
    pizza->get_price();
    delete pizza;
    }

    return 0;
    }
    ----------------------------------------8<------------------------

    Regards.
     
    Stefano Sabatini, Oct 24, 2008
    #4
  5. Stefano Sabatini

    anon Guest

    > ----------------------------------------8<------------------------
    > #include <string>
    > #include <map>
    > #include <iostream>
    >
    > class Pizza {
    > public:
    > virtual void get_price() = 0;
    > };
    >
    > class HamAndMushroomPizza: public Pizza {
    > public:
    > virtual void get_price() {
    > std::cout << "Ham and Mushroom: $8.5" << std::endl;
    > }
    >
    > static Pizza* create_pizza() {
    > return new HamAndMushroomPizza;
    > }
    > };
    >
    > class DeluxePizza : public Pizza {
    > public:
    > virtual void get_price() {
    > std::cout << "Deluxe: $10.5" << std::endl;
    > }
    >
    > static Pizza* create_pizza() {
    > return new DeluxePizza;
    > }
    > };
    >
    > class SeafoodPizza : public Pizza {
    > public:
    > virtual void get_price() {
    > std::cout << "Seafood: $11.5" << std::endl;
    > }
    >
    > static Pizza* create_pizza() {
    > return new SeafoodPizza;
    > }
    > };
    >
    > typedef Pizza* (*pizza_creator_ptr)(void);
    >
    > class PizzaFactory {
    > private:
    > static std::map<std::string, pizza_creator_ptr> creators;
    >
    > void init() {
    > PizzaFactory::creators["Deluxe"] = &DeluxePizza::create_pizza;
    > PizzaFactory::creators["Ham and Mushroom"] = &HamAndMushroomPizza::create_pizza;
    > PizzaFactory::creators["Seafood"] = &SeafoodPizza::create_pizza;
    > }
    >
    > public:
    > static PizzaFactory* get_instance()
    > {
    > static PizzaFactory * instance = 0;
    > if (!instance) {
    > instance = new PizzaFactory;
    > instance->init();
    > }
    > return instance;
    > }
    >
    > Pizza* create_pizza(const std::string& type) {
    > std::map<std::string, pizza_creator_ptr>::iterator it;
    > if ((it = PizzaFactory::creators.find(type)) != creators.end())
    > return (*(it->second))();
    > else
    > return 0;
    > }
    > };
    >
    > std::map<std::string, pizza_creator_ptr> PizzaFactory::creators;
    >
    > //usage
    > int main() {
    > PizzaFactory* factory = PizzaFactory::get_instance();
    > Pizza *pizza = 0;
    >
    > if (pizza = factory->create_pizza("Default")) {
    > pizza->get_price();
    > delete pizza;
    > }
    >
    > if (pizza = factory->create_pizza("Ham and Mushroom")) {
    > pizza->get_price();
    > delete pizza;
    > }
    >
    > if (pizza = factory->create_pizza("Seafood")) {
    > pizza->get_price();
    > delete pizza;
    > }
    >
    > return 0;
    > }
    > ----------------------------------------8<------------------------


    I think there is another problem with this example: the Pizza class is
    missing the virtual destructor.
     
    anon, Oct 24, 2008
    #5
  6. Stefano Sabatini

    Default User Guest

    Pete Becker wrote:


    > In general, though, don't write complicated types on the fly
    > (pointers to functions are complicated types). Use typedefs:
    >
    > typedef Pizza*(*creator)();
    > std::map<std::string, creator> creators;


    I tend to find it a bit more readable to do something like:

    typedef Pizza* CreatorFuncType();
    std::map<std::string, CreatorFuncType*> creators;





    Brian
     
    Default User, Oct 24, 2008
    #6
  7. Stefano Sabatini

    Default User Guest

    Pete Becker wrote:

    > On 2008-10-24 14:20:09 -0400, "Default User"
    > <> said:
    >
    > > Pete Becker wrote:
    > >
    > >
    > > > In general, though, don't write complicated types on the fly
    > > > (pointers to functions are complicated types). Use typedefs:
    > > >
    > > > typedef Pizza*(*creator)();
    > >>std::map<std::string, creator> creators;

    > >
    > > I tend to find it a bit more readable to do something like:
    > >
    > > typedef Pizza* CreatorFuncType();
    > > std::map<std::string, CreatorFuncType*> creators;
    > >

    >
    > Thus making use of the only way that a function type can be used in
    > C: as the target of the address-of operator.


    You can use it in a declaration (but not definition) of a function as
    well, I believe.



    Brian
     
    Default User, Oct 24, 2008
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    13
    Views:
    13,036
    Kai-Uwe Bux
    Jan 22, 2007
  2. Philipp
    Replies:
    26
    Views:
    2,444
    Ramon F Herrera
    Nov 25, 2007
  3. TimC
    Replies:
    6
    Views:
    2,152
    CBFalconer
    Mar 7, 2009
  4. TimC
    Replies:
    2
    Views:
    4,550
    James Kanze
    Mar 7, 2009
  5. Juha Nieminen
    Replies:
    16
    Views:
    2,692
    kwikius
    May 29, 2009
Loading...

Share This Page