[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

template static member

chgans

9/27/2008 1:50:00 PM

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
5 Answers

Ian Collins

9/27/2008 8:32:00 PM

0

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.

szymonwlodarski

9/27/2008 8:46:00 PM

0

On Sep 27, 3:49 pm, chgans <chg...@googlemail.com> 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

Jim Z. Shi

9/28/2008 2:52:00 AM

0



chgans wrote:
> Hi all,
>
>
> // 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;

change it into:
template<>
std::map<std::string, int> BaseT<DerivedT>::gMap =
std::map<std::string, 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

James Kanze

9/28/2008 7:23:00 AM

0

On Sep 27, 10:45 pm, SzymonWlodar...@gmail.com wrote:
> On Sep 27, 3:49 pm, chgans <chg...@googlemail.com> 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:james.kanze@gmail.com
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

9/28/2008 11:26:00 PM

0

On Sep 28, 8:23 am, James Kanze <james.ka...@gmail.com> wrote:
> On Sep 27, 10:45 pm, SzymonWlodar...@gmail.com wrote:
>
>
>
> > On Sep 27, 3:49 pm, chgans <chg...@googlemail.com> 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:james.ka...@gmail.com
> 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