C++ Static Template Member, One Instance for Each Template Type

C++ static template member, one instance for each template type?

Static members are different for each diffrent template initialization. This is because each template initialization is a different class that is generated by the compiler the first time it encounters that specific initialization of the template.

The fact that static member variables are different is shown by this code:

#include <iostream>

template <class T> class Foo {
public:
static int bar;
};

template <class T>
int Foo<T>::bar;

int main(int argc, char* argv[]) {
Foo<int>::bar = 1;
Foo<char>::bar = 2;

std::cout << Foo<int>::bar << "," << Foo<char>::bar;
}

Which results in

1,2

Sharing static members between template instantiations? (impossible?)

You could add a non-templated base class and move lookupTable into that class:

class Base
{
protected:
static map<string, internal_t> lookupTable
};

template<class T, int N>
class SpecialArray : Base
{
//...
};

How to make one instance only of class template static member in case of several shared libraries?

For GCC you can use:

#define EXPORT __attribute__((visibility("default")))

I've tested it using CMake with the following setup mylib.h:

#define EXPORT __attribute__((visibility("default")))

template<typename T>
struct A
{
EXPORT static int x;
};

mylib.cpp

#include "mylib.h"

template<> int A<int>::x = 1;
template<> int A<bool>::x = false;

main.cpp

std::cout << "A<int>: " << A<int>::x << std::endl;
std::cout << "A<bool>: " << A<bool>::x << std::endl;

with output:

A<int>: 1
A<bool>: 0

CMakeLists.txt

# Change the default to hidden, then you need to explicitly set it
# Thus, normally, you shouldn't have the problem
add_compile_options(-fvisibility=hidden) # only for testing the EXPORT define

add_library(mylib SHARED mylib.cpp)
add_executable(example main.cpp main2.cpp) # Main2 also used mylib
target_link_libraries(example mylib)

Thus, for a universal option I will propose to add this define to your if else define macro list.

Static constexpr member of a template class different for each instance?

Foo<int, 10> and Foo<int, 12> are different classes - they just share the same template. All instances of Foo<int, 10> will share the same containerLen, as will all instances of Foo<int, 12>; but the two classes will not share a common value.

What should happen to template class static member variables with definition in the .h file

From N3290, 14.6:

A [...] static data member of a class template shall be defined in
every translation unit in which it is implicitly instantiated [...], unless the corresponding specialization is explicitly instantiated [...] .

Typically, you put the static member definition in the header file, along with the template class definition:

template <typename T>
class Foo
{
static int n; // declaration
};

template <typename T> int Foo<T>::n; // definition

To expand on the concession: If you plan on using explicit instantiations in your code, like:

template <> int Foo<int>::n = 12;

then you must not put the templated definition in the header if Foo<int> is also used in other TUs other than the one containing the explicit instantiation, since you'd then get multiple definitions.

However, if you do need to set an initial value for all possible parameters without using explicit instantiation, you have to put that in the header, e.g. with TMP:

// in the header
template <typename T> int Foo<T>::n = GetInitialValue<T>::value; // definition + initialization

Static member of template

The static constant member assigned there changes depending on the value that is being passed by the template parameter. Shorten it to something like this:

template<int X>
struct foo {
static const int value = X;
};

You wouldn't expect foo<10>::value to be equal to foo<11>::value would you? This is commonly used in template meta programming because the value of that static constant depends on a template parameter.

How to implement static variable functionality for templates in C++

This is a false premise:

However for templates I can't have just one static variables for all template instances.

Yes you can:

#include <iostream>

struct Base {
static int counter;
Base() { counter++; }
};

int Base::counter = 0;

template <typename T>
struct Foo : Base {};

int main(int argc, char** argv) {
Foo<int> x;
Foo<double> y;
Foo<float> z;
std::cout << Base::counter;
}

Output:

3

Actually this isn't something specific to your current problem. In general anything not depending on the template parameter can be moved to a non-template base class.

Can template classes have static members in C++

Yes. The static member is declared or defined inside the template< … > class { … } block. If it is declared but not defined, then there must be another declaration which provides the definition of the member.

template< typename T >
class has_static {
// inline method definition: provides the body of the function.
static void meh() {}

// method declaration: definition with the body must appear later
static void fuh();

// definition of a data member (i.e., declaration with initializer)
// only allowed for const integral members
static int const guh = 3;

// declaration of data member, definition must appear later,
// even if there is no initializer.
static float pud;
};

// provide definitions for items not defined in class{}
// these still go in the header file

// this function is also inline, because it is a template
template< typename T >
void has_static<T>::fuh() {}

/* The only way to templatize a (non-function) object is to make it a static
data member of a class. This declaration takes the form of a template yet
defines a global variable, which is a bit special. */
template< typename T >
float has_static<T>::pud = 1.5f; // initializer is optional

A separate static member is created for each parameterization of the template. It is not possible to have a single member shared across all classes generated by the template. For that, you must define another object outside the template. A partially-specialized traits class might help with that.

Error while using a static data member template

Yes this is a typo in the book. The problem is that you've specified an initializer for the static data member template even though it is not inline.

Solution

There are 2 ways to solve this problem both of which are given below.

Method 1: C++17

In C++17, you can make use of the keyword inline.

class Collection {
public:


template<typename T>
inline static T zero = 0; //note the keyword inline here
};
//no need for out of class definition of static data member template
int main(){
int x =Collection::zero<int>;
}

Method 2: C++14

In this case you need to remove the initializer 0 from the in-class declaration of the static data member template.

class Collection {
public:

template<typename T>
static T zero ; //note initializer 0 removed from here since this is a declaration
};

template<typename T> T Collection::zero = 0;
int main(){
int x =Collection::zero<int>;
}


Related Topics



Leave a reply



Submit