'*' cannot appear in a constant-expression problem

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stefano Sabatini

    '*' cannot appear in a constant-expression problem

    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 HamAndMushroomP izza: public Pizza {
    public:
    virtual void get_price(){
    std::cout << "Ham and Mushroom: $8.5" << std::endl;
    }

    static Pizza* create_pizza()
    {
    return new HamAndMushroomP izza;
    }
    };

    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::s tring, (Pizza *)(*)()creators ;

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

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

    static Pizza* create_pizza(co nst std::string type) {
    PString type = config.GetAttri bute("type");
    if ((it = creators.find(t ype) != creators.end()) )
    return (it->second)();
    else
    return 0;
    }
    };

    // usage
    int main() {
    PizzaFactory* factory = PizzaFactory::g et_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.c xx -c -o PizzaFactory2.o
    PizzaFactory2.c xx:50: error: `*' cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: a function call cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: `*' cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: a function call cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: a function call cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: template argument 2 is invalid

    The exact line of the error is:
    static std::map<std::s tring, (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.
  • Pete Becker

    #2
    Re: '*' cannot appear in a constant-expression problem

    On 2008-10-24 05:46:59 -0400, Stefano Sabatini
    <stefano.sabati ni@caos.orgsaid :

    [~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.c xx -c -o PizzaFactory2.o
    PizzaFactory2.c xx:50: error: `*' cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: a function call cannot appear in a
    constant-expression
    PizzaFactory2.c xx:50: error: `*' cannot appear in a constant-expression
    PizzaFactory2.c xx:50: error: a function call cannot appear in a
    constant-expression
    PizzaFactory2.c xx:50: error: a function call cannot appear in a
    constant-expression
    PizzaFactory2.c xx:50: error: template argument 2 is invalid
    >
    The exact line of the error is:
    static std::map<std::s tring, (Pizza *)(*)()creators ;
    >
    #include <string>
    #include <map>
    class Pizza;
    std::map<std::s tring, (Pizza*)(*)()cr eators;

    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::s tring, Pizza*(*)()crea tors;

    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::s tring, creatorcreators ;

    --
    Pete
    Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
    Standard C++ Library Extensions: a Tutorial and Reference
    (www.petebecker.com/tr1book)

    Comment

    • Stefano Sabatini

      #3
      Re: '*' cannot appear in a constant-expression problem

      On 2008-10-24, Stefano Sabatini <stefano.sabati ni@caos.orgwrot e:
      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.c xx -c -o PizzaFactory2.o
      PizzaFactory2.c xx:50: error: `*' cannot appear in a constant-expression
      PizzaFactory2.c xx:50: error: a function call cannot appear in a constant-expression
      PizzaFactory2.c xx:50: error: `*' cannot appear in a constant-expression
      PizzaFactory2.c xx:50: error: a function call cannot appear in a constant-expression
      PizzaFactory2.c xx:50: error: a function call cannot appear in a constant-expression
      PizzaFactory2.c xx:50: error: template argument 2 is invalid
      >
      The exact line of the error is:
      static std::map<std::s tring, (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_f n_ptr)();

      and then use the map like this:
      static map<std::string , pizza_creator_f n_ptrcreators;

      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 HamAndMushroomP izza: public Pizza {
      public:
      virtual void get_price() {
      std::cout << "Ham and Mushroom: $8.5" << std::endl;
      }

      static Pizza* create_pizza() {
      return new HamAndMushroomP izza;
      }
      };

      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::s tring, pizza_creator_f n_ptrcreators;

      void init() {
      creators["Deluxe"] = &DeluxePizza::c reate_pizza;
      creators["Ham and Mushroom"] = &HamAndMushroom Pizza::create_p izza;
      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(co nst std::string& type) {
      std::map<std::s tring, pizza_creator_f n_ptr>::iterato r it;
      if ((it = creators.find(t ype)) != creators.end())
      return (*(it->second))();
      else
      return 0;
      }
      };

      //usage
      int main() {
      PizzaFactory* factory = PizzaFactory::g et_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.

      Comment

      • Stefano Sabatini

        #4
        Re: '*' cannot appear in a constant-expression problem

        On 2008-10-24, Pete Becker <pete@versatile coding.comwrote :
        On 2008-10-24 05:46:59 -0400, Stefano Sabatini
        ><stefano.sabat ini@caos.orgsai d:
        >
        [~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.c xx -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::s tring, (Pizza *)(*)()creators ;
        >>
        >
        #include <string>
        #include <map>
        class Pizza;
        std::map<std::s tring, (Pizza*)(*)()cr eators;
        >
        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::s tring, Pizza*(*)()crea tors;
        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::s tring, creatorcreators ;
        Yes, good advice.

        Many thanks, regards.

        Comment

        • Stefano Sabatini

          #5
          Re: '*' cannot appear in a constant-expression problem

          On 2008-10-24, Stefano Sabatini <stefano.sabati ni@caos.orgwrot e:
          On 2008-10-24, Stefano Sabatini <stefano.sabati ni@caos.orgwrot e:
          >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.c xx -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::s tring, (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_f n_ptr)();
          >
          and then use the map like this:
          static map<std::string , pizza_creator_f n_ptrcreators;
          >
          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::s tring, pizza_creator_p trPizzaFactory: :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 HamAndMushroomP izza: public Pizza {
          public:
          virtual void get_price() {
          std::cout << "Ham and Mushroom: $8.5" << std::endl;
          }

          static Pizza* create_pizza() {
          return new HamAndMushroomP izza;
          }
          };

          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::s tring, pizza_creator_p trcreators;

          void init() {
          PizzaFactory::c reators["Deluxe"] = &DeluxePizza::c reate_pizza;
          PizzaFactory::c reators["Ham and Mushroom"] = &HamAndMushroom Pizza::create_p izza;
          PizzaFactory::c reators["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(co nst std::string& type) {
          std::map<std::s tring, pizza_creator_p tr>::iterator it;
          if ((it = PizzaFactory::c reators.find(ty pe)) != creators.end())
          return (*(it->second))();
          else
          return 0;
          }
          };

          std::map<std::s tring, pizza_creator_p trPizzaFactory: :creators;

          //usage
          int main() {
          PizzaFactory* factory = PizzaFactory::g et_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.

          Comment

          • anon

            #6
            Re: '*' cannot appear in a constant-expression problem

            ----------------------------------------8<------------------------
            #include <string>
            #include <map>
            #include <iostream>
            >
            class Pizza {
            public:
            virtual void get_price() = 0;
            };
            >
            class HamAndMushroomP izza: public Pizza {
            public:
            virtual void get_price() {
            std::cout << "Ham and Mushroom: $8.5" << std::endl;
            }
            >
            static Pizza* create_pizza() {
            return new HamAndMushroomP izza;
            }
            };
            >
            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::s tring, pizza_creator_p trcreators;
            >
            void init() {
            PizzaFactory::c reators["Deluxe"] = &DeluxePizza::c reate_pizza;
            PizzaFactory::c reators["Ham and Mushroom"] = &HamAndMushroom Pizza::create_p izza;
            PizzaFactory::c reators["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(co nst std::string& type) {
            std::map<std::s tring, pizza_creator_p tr>::iterator it;
            if ((it = PizzaFactory::c reators.find(ty pe)) != creators.end())
            return (*(it->second))();
            else
            return 0;
            }
            };
            >
            std::map<std::s tring, pizza_creator_p trPizzaFactory: :creators;
            >
            //usage
            int main() {
            PizzaFactory* factory = PizzaFactory::g et_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.

            Comment

            • Default User

              #7
              Re: '*' cannot appear in a constant-expression problem

              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::s tring, creatorcreators ;
              I tend to find it a bit more readable to do something like:

              typedef Pizza* CreatorFuncType ();
              std::map<std::s tring, CreatorFuncType *creators;





              Brian



              Comment

              • Pete Becker

                #8
                Re: '*' cannot appear in a constant-expression problem

                On 2008-10-24 14:20:09 -0400, "Default User" <defaultuserbr@ yahoo.comsaid:
                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, creatorcreators ;
                >
                I tend to find it a bit more readable to do something like:
                >
                typedef Pizza* CreatorFuncType ();
                std::map<std::s tring, 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.

                --
                Pete
                Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
                Standard C++ Library Extensions: a Tutorial and Reference
                (www.petebecker.com/tr1book)

                Comment

                • Default User

                  #9
                  Re: '*' cannot appear in a constant-expression problem

                  Pete Becker wrote:
                  On 2008-10-24 14:20:09 -0400, "Default User"
                  <defaultuserbr@ yahoo.comsaid:
                  >
                  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, creatorcreators ;
                  I tend to find it a bit more readable to do something like:

                  typedef Pizza* CreatorFuncType ();
                  std::map<std::s tring, 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

                  Comment

                  Working...