template static member

Discussion in 'C++' started by chgans, Sep 27, 2008.

  1. chgans

    chgans Guest

    Hi all,

    I'm having difficulties with some template static member, especially
    when this member is a template instance, for example:
    ----
    template<typename 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::string, int> gMap;
    };

    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("Derived");

    // This one gives me a linkage error:
    // In function BaseT<DerivedT>::UseMap(...):
    // undefined reference to BaseT<DerivedT>::gMap
    template<>
    std::map<std::string, int> BaseT<DerivedT>::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
    chgans, Sep 27, 2008
    #1
    1. Advertising

  2. chgans

    Ian Collins Guest

    chgans wrote:
    > Hi all,
    >
    > I'm having difficulties with some template static member, especially
    > when this member is a template instance, for example:
    > ----
    > template<typename 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::string, int> gMap;
    > };
    >
    > 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("Derived");
    >
    > // This one gives me a linkage error:
    > // In function BaseT<DerivedT>::UseMap(...):
    > // undefined reference to BaseT<DerivedT>::gMap
    > template<>
    > std::map<std::string, int> BaseT<DerivedT>::gMap;
    >

    Why try and specialise?

    template <typename T>
    std::map<std::string, int> BaseT<T>::gMap;

    Will be fine.

    --
    Ian Collins.
    Ian Collins, Sep 27, 2008
    #2
    1. Advertising

  3. chgans

    Guest

    On Sep 27, 3:49 pm, chgans <> wrote:
    > Hi all,
    >
    > I'm having difficulties with some template static member, especially
    > when this member is a template instance, for example:
    > ----
    > template<typename 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::string, int> gMap;
    >
    > };
    >
    > 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("Derived");
    >
    > // This one gives me a linkage error:
    > // In function BaseT<DerivedT>::UseMap(...):
    > // undefined reference to BaseT<DerivedT>::gMap
    > template<>
    > std::map<std::string, int> BaseT<DerivedT>::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::string, int> BaseT< T >::gMap;

    or:

    template<>
    std::map<std::string, int> BaseT< 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
    , Sep 27, 2008
    #3
  4. chgans

    James Kanze Guest

    On Sep 27, 10:45 pm, wrote:
    > On Sep 27, 3:49 pm, chgans <> wrote:


    > > I'm having difficulties with some template static member,
    > > especially when this member is a template instance, for
    > > example:
    > > ----
    > > template<typename 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::string, int> gMap;
    > > };


    > > 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("Derived");


    > > // This one gives me a linkage error:
    > > // In function BaseT<DerivedT>::UseMap(...):
    > > // undefined reference to BaseT<DerivedT>::gMap
    > > template<>
    > > std::map<std::string, int> BaseT<DerivedT>::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::string, int> BaseT< T >::gMap;


    > or:


    > template<>
    > std::map<std::string, int> BaseT< 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:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Sep 28, 2008
    #4
  5. chgans

    chgans Guest

    On Sep 28, 8:23 am, James Kanze <> wrote:
    > On Sep 27, 10:45 pm, wrote:
    >
    >
    >
    > > On Sep 27, 3:49 pm, chgans <> wrote:
    > > > I'm having difficulties with some template static member,
    > > > especially when this member is a template instance, for
    > > > example:
    > > > ----
    > > > template<typename 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::string, int> gMap;
    > > > };
    > > > 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("Derived");
    > > > // This one gives me a linkage error:
    > > > // In function BaseT<DerivedT>::UseMap(...):
    > > > // undefined reference to BaseT<DerivedT>::gMap
    > > > template<>
    > > > std::map<std::string, int> BaseT<DerivedT>::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::string, int> BaseT< T >::gMap;
    > > or:
    > > template<>
    > > std::map<std::string, int> BaseT< 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:
    > Conseils en informatique orientée objet/
    >                    Beratung in objektorientierter Datenverarbeitung
    > 9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    chgans, Sep 29, 2008
    #5
    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. Frederiek
    Replies:
    1
    Views:
    380
    Thomas Tutone
    Sep 14, 2006
  2. dolphin
    Replies:
    3
    Views:
    1,337
    Pete Becker
    Dec 5, 2007
  3. Hicham Mouline
    Replies:
    0
    Views:
    431
    Hicham Mouline
    Apr 23, 2009
  4. Hicham Mouline
    Replies:
    1
    Views:
    412
    Michael DOUBEZ
    Apr 24, 2009
  5. Replies:
    1
    Views:
    289
Loading...

Share This Page