template static member

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

    template static member

    Hi all,

    I'm having difficulties with some template static member, especially
    when this member is a template instance, for example:
    ----
    template<typena me T>
    class BaseT
    {
    public:
    static void UseMap (const std::string &key, int value)
    {
    std::cout << gName << std::endl;
    gMap[key] = value;
    }

    private:
    static const std::string gName;
    static std::map<std::s tring, intgMap;
    };

    class DerivedT : public BaseT<DerivedT>
    {
    public:
    // Some code soon or late....
    };

    // Now the specialization for BaseT<DerivedT>

    // This one work fine
    template<>
    const std::string BaseT<DerivedT> ::gName("Derive d");

    // This one gives me a linkage error:
    // In function BaseT<DerivedT> ::UseMap(...):
    // undefined reference to BaseT<DerivedT> ::gMap
    template<>
    std::map<std::s tring, intBaseT<Derive dT>::gMap;

    int main (int argc, char** argv)
    {
    DerivedT a;
    a.UseMap ("test", 4);
    }
    ----

    So, i was wandering, if there is a special way to declare a static
    member (which use the std::map template) of a template.

    Later everything will be split up into several files, but for now i'm
    using a single c++ source file to try to solve this problem. I've
    tried with g++ 4.3.0 (x86_64, RH FC9) and a arm-linux-g++ 3.4, both
    gives same results.

    Thanks,
    Christian
  • Ian Collins

    #2
    Re: template static member

    chgans wrote:
    Hi all,
    >
    I'm having difficulties with some template static member, especially
    when this member is a template instance, for example:
    ----
    template<typena me T>
    class BaseT
    {
    public:
    static void UseMap (const std::string &key, int value)
    {
    std::cout << gName << std::endl;
    gMap[key] = value;
    }
    >
    private:
    static const std::string gName;
    static std::map<std::s tring, intgMap;
    };
    >
    class DerivedT : public BaseT<DerivedT>
    {
    public:
    // Some code soon or late....
    };
    >
    // Now the specialization for BaseT<DerivedT>
    >
    // This one work fine
    template<>
    const std::string BaseT<DerivedT> ::gName("Derive d");
    >
    // This one gives me a linkage error:
    // In function BaseT<DerivedT> ::UseMap(...):
    // undefined reference to BaseT<DerivedT> ::gMap
    template<>
    std::map<std::s tring, intBaseT<Derive dT>::gMap;
    >
    Why try and specialise?

    template <typename T>
    std::map<std::s tring, intBaseT<T>::gM ap;

    Will be fine.

    --
    Ian Collins.

    Comment

    • SzymonWlodarski@gmail.com

      #3
      Re: template static member

      On Sep 27, 3:49 pm, chgans <chg...@googlem ail.comwrote:
      Hi all,
      >
      I'm having difficulties with some template static member, especially
      when this member is a template instance, for example:
      ----
      template<typena me T>
      class BaseT
      {
      public:
      static void UseMap (const std::string &key, int value)
      {
      std::cout << gName << std::endl;
      gMap[key] = value;
      }
      >
      private:
      static const std::string gName;
      static std::map<std::s tring, intgMap;
      >
      };
      >
      class DerivedT : public BaseT<DerivedT>
      {
      public:
      // Some code soon or late....
      >
      };
      >
      // Now the specialization for BaseT<DerivedT>
      >
      // This one work fine
      template<>
      const std::string BaseT<DerivedT> ::gName("Derive d");
      >
      // This one gives me a linkage error:
      // In function BaseT<DerivedT> ::UseMap(...):
      // undefined reference to BaseT<DerivedT> ::gMap
      template<>
      std::map<std::s tring, intBaseT<Derive dT>::gMap;
      >
      int main (int argc, char** argv)
      {
      DerivedT a;
      a.UseMap ("test", 4);}
      >
      ----
      >
      So, i was wandering, if there is a special way to declare a static
      member (which use the std::map template) of a template.
      >
      Later everything will be split up into several files, but for now i'm
      using a single c++ source file to try to solve this problem. I've
      tried with g++ 4.3.0 (x86_64, RH FC9) and a arm-linux-g++ 3.4, both
      gives same results.
      >
      Thanks,
      Christian
      It seems that if you specialize a static member you can't do it with a
      default constructor. You can either write:

      template< class T >
      std::map<std::s tring, intBaseT< T >::gMap;

      or:

      template<>
      std::map<std::s tring, intBaseT< DerivedT >::gMap( anotherMap );

      However, I tested it using only one compiler (g++ 4.1.2) and I did not
      look into the Standard so I am not sure that it is what it requires.

      Example:

      template< class T >
      struct A
      {
      static void
      push( T const & v )
      {
      vec.push_back( v );
      }

      static std::vector< T vec;
      };

      template< class T >
      std::vector< T A< T >::vec;

      /*
      template<>
      std::vector< double A< double >::vec; // won't work
      */

      template<>
      std::vector< double A< double >::vec( 10 ); // ok

      int
      main()
      {
      A< int >::push( 10 );
      A< double >::push( 10.0 );
      }

      --
      Szymon

      Comment

      • Jim Z. Shi

        #4
        Re: template static member



        chgans wrote:
        Hi all,
        >
        >
        // Now the specialization for BaseT<DerivedT>
        >
        // This one work fine
        template<>
        const std::string BaseT<DerivedT> ::gName("Derive d");
        >
        // This one gives me a linkage error:
        // In function BaseT<DerivedT> ::UseMap(...):
        // undefined reference to BaseT<DerivedT> ::gMap
        template<>
        std::map<std::s tring, intBaseT<Derive dT>::gMap;
        change it into:
        template<>
        std::map<std::s tring, intBaseT<Derive dT>::gMap =
        std::map<std::s tring, int>();

        to give gMap a memory space.

        hth,
        Jim
        >
        int main (int argc, char** argv)
        {
        DerivedT a;
        a.UseMap ("test", 4);
        }
        ----
        >
        So, i was wandering, if there is a special way to declare a static
        member (which use the std::map template) of a template.
        >
        Later everything will be split up into several files, but for now i'm
        using a single c++ source file to try to solve this problem. I've
        tried with g++ 4.3.0 (x86_64, RH FC9) and a arm-linux-g++ 3.4, both
        gives same results.
        >
        Thanks,
        Christian

        Comment

        • James Kanze

          #5
          Re: template static member

          On Sep 27, 10:45 pm, SzymonWlodar... @gmail.com wrote:
          On Sep 27, 3:49 pm, chgans <chg...@googlem ail.comwrote:
          I'm having difficulties with some template static member,
          especially when this member is a template instance, for
          example:
          ----
          template<typena me T>
          class BaseT
          {
          public:
          static void UseMap (const std::string &key, int value)
          {
          std::cout << gName << std::endl;
          gMap[key] = value;
          }
          private:
          static const std::string gName;
          static std::map<std::s tring, intgMap;
          };
          class DerivedT : public BaseT<DerivedT>
          {
          public:
          // Some code soon or late....
          };
          // Now the specialization for BaseT<DerivedT>
          // This one work fine
          template<>
          const std::string BaseT<DerivedT> ::gName("Derive d");
          // This one gives me a linkage error:
          // In function BaseT<DerivedT> ::UseMap(...):
          // undefined reference to BaseT<DerivedT> ::gMap
          template<>
          std::map<std::s tring, intBaseT<Derive dT>::gMap;
          int main (int argc, char** argv)
          {
          DerivedT a;
          a.UseMap ("test", 4);
          }
          ----
          So, i was wandering, if there is a special way to declare a
          static member (which use the std::map template) of a
          template.
          It seems that if you specialize a static member you can't do
          it with a default constructor. You can either write:
          template< class T >
          std::map<std::s tring, intBaseT< T >::gMap;
          or:
          template<>
          std::map<std::s tring, intBaseT< DerivedT >::gMap( anotherMap );
          However, I tested it using only one compiler (g++ 4.1.2) and I
          did not look into the Standard so I am not sure that it is
          what it requires.
          Note that a specialization is not a template, but rather a
          declaration or definition of a non-template entity with a name
          that looks like a template instantiation, to be used instead of
          the instantiation.

          Givan that, the basic problem in this is that without an
          initializer, the compiler interprets the static member
          specialization as a declaration, not a definition, and since
          it's not a template, you need a definition (in one, and only
          one, translation unit). See §14.7.3/15:

          An explicit specialization of a static data member of a
          template is a definition if the declaration includes an
          initializer; otherwise, it is a declaration. [Note:
          there is no syntax for the definition of a static data
          member of a template which requires default
          initialization.

          template<X Q<int>::x ;

          This is a declaration regardless of whether X can be
          default initialized.]

          Note the note!

          Note too that formally, you can only provide a single
          definition, which means that the definition should be in a
          source file, and not in a header; i.e.:

          In the header:
          template< class T >
          std::map< std::string, int BaseT< DerivedT >::gMap ;

          and then in one and only one source file (which includes the
          header):
          template< class T >
          std::map< std::string, int BaseT< DerivedT >::gMap(
          std::map< std::string, int BaseT< DerivedT >() ) ;
          (Luckily, we can use the copy constructor in this case.)

          --
          James Kanze (GABI Software) email:james.kan ze@gmail.com
          Conseils en informatique orientée objet/
          Beratung in objektorientier ter Datenverarbeitu ng
          9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

          Comment

          • chgans

            #6
            Re: template static member

            On Sep 28, 8:23 am, James Kanze <james.ka...@gm ail.comwrote:
            On Sep 27, 10:45 pm, SzymonWlodar... @gmail.com wrote:
            >
            >
            >
            On Sep 27, 3:49 pm, chgans <chg...@googlem ail.comwrote:
            I'm having difficulties with some template static member,
            especially when this member is a template instance, for
            example:
            ----
            template<typena me T>
            class BaseT
            {
            public:
              static void UseMap (const std::string &key, int value)
              {
                std::cout << gName << std::endl;
                gMap[key] = value;
              }
            private:
              static const std::string gName;
              static std::map<std::s tring, intgMap;
            };
            class DerivedT : public BaseT<DerivedT>
            {
            public:
               // Some code soon or late....
            };
            // Now the specialization for BaseT<DerivedT>
            // This one work fine
            template<>
            const std::string BaseT<DerivedT> ::gName("Derive d");
            // This one gives me a linkage error:
            // In function BaseT<DerivedT> ::UseMap(...):
            // undefined reference to BaseT<DerivedT> ::gMap
            template<>
            std::map<std::s tring, intBaseT<Derive dT>::gMap;
            int main (int argc, char** argv)
            {
              DerivedT a;
              a.UseMap ("test", 4);
            }
            ----
            So, i was wandering, if there is a special way to declare a
            static member (which use the std::map template) of a
            template.
            It seems that if you specialize a static member you can't do
            it with a default constructor. You can either write:
            template< class T >
            std::map<std::s tring, intBaseT< T >::gMap;
            or:
            template<>
            std::map<std::s tring, intBaseT< DerivedT >::gMap( anotherMap );
            However, I tested it using only one compiler (g++ 4.1.2) and I
            did not look into the Standard so I am not sure that it is
            what it requires.
            >
            Note that a specialization is not a template, but rather a
            declaration or definition of a non-template entity with a name
            that looks like a template instantiation, to be used instead of
            the instantiation.
            >
            Givan that, the basic problem in this is that without an
            initializer, the compiler interprets the static member
            specialization as a declaration, not a definition, and since
            it's not a template, you need a definition (in one, and only
            one, translation unit).  See §14.7.3/15:
            >
                An explicit specialization of a static data member of a
                template is a definition if the declaration includes an
                initializer; otherwise, it is a declaration. [Note:
                there is no syntax for the definition of a static data
                member of a template which requires default
                initialization.
            >
                    template<X Q<int>::x ;
            >
                This is a declaration regardless of whether X can be
                default initialized.]
            >
            Note the note!
            >
            Note too that formally, you can only provide a single
            definition, which means that the definition should be in a
            source file, and not in a header; i.e.:
            >
            In the header:
                template< class T >
                std::map< std::string, int BaseT< DerivedT >::gMap ;
            >
            and then in one and only one source file (which includes the
            header):
                template< class T >
                std::map< std::string, int BaseT< DerivedT >::gMap(
                        std::map< std::string, int BaseT< DerivedT >() ) ;
            (Luckily, we can use the copy constructor in this case.)
            Thank you all,
            Problem solved now! :)

            >
            --
            James Kanze (GABI Software)             email:james.ka. ..@gmail.com
            Conseils en informatique orientée objet/
                               Beratung in objektorientier ter Datenverarbeitu ng
            9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

            Comment

            Working...