HelloGoodbye
HelloGoodbye

Reputation: 3902

How to initialize a static const member of type depending on T in a templated class?

Given the following class

template <class T>
class A {
    static const B<T> member;
};

how can I instantiate member for each class A<T> separately?

Upvotes: 3

Views: 181

Answers (1)

miguel.martin
miguel.martin

Reputation: 1627

Simple. As you would with any other static non-integral type.

template <class T>
class A {
    static const B<T> member;
};


template <class T>
const B<T> A<T>::member/*(optional-args)*/;

In order to allocate member differently for different types of T, you must use template specialisation.

To start the template specialisation you must use this syntax:

template<>
// ... explicit definition

The syntax for the explicit definition is basically the same syntax as:

template <class T>
const B<T> A<T>::member/*(optional-args)*/;

Except, instead of template <class T>, you use template<>, and where T is, you put the actual type.

For example:

template<>
const B<type> A<type>::member(args);

NOTE: If you wish to call the default constructor with template specialisation in this scenario, please see the EDIT below.

You can substitute type for any type you wish. With this you can provide different arguments for each possible type. Although if you specialise too much, you should consider if your design is really suited to use templates.

Here it is in action (online), feel free to clone and play around with it.

I thought I'd mention that the declaration must be where the template class is located. In other words, if A is declared in the header, you must also declare the allocation for member in the header file. You can alternatively use an inline file (.inl) and #include the .inl file in the header file that the template class is declared.

EDIT:

It seems that in C++98, the following syntax to call the default constructor does not compile under GCC or clang, if you refer to the member variable:

 template <>
 const B<type> A<type>::member/*()*/;

Where type is any type.

However the following does:

 template <class T>
 const B<T> A<T>::member/*()*/;

I'm not sure if this is a bug, or just incorrect syntax. I recommend instead to do the following:

 template <>
 const B<type> A<type>::member = B<type>();

Or if you are using C++11, you can use curly brackets to call the default-constructor, like so:

 template <>
 const B<type> A<type>::member{};

If you use regular brackets, the compiler will thing it is a static function within the A<type> class, and if you use no brackets, you will get an undefined reference to 'A<type>::member' linker error. Which you can see here.

Here is the discussion that Aaron and I discovered this error.

Upvotes: 6

Related Questions