Fedor
Fedor

Reputation: 21307

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

I have a template class with a static member, for simplicity:

template<typename T>
struct A
{
    static inline int x = 1;
};

But if I include the header with struct A definition in several shared-libraries, each of them will have its own instance of A<T>::x. And I would like to have the instance of A<T>::x (for some fixed list of T-types) only in some one shared library, and all other libraries accessing it.

In Visual Studio I can do it by writing in the header

#ifdef _WIN32
#   ifdef MY_LIB_EXPORT
#       define MY_LIB_API __declspec(dllexport)
#   else
#       define MY_LIB_API __declspec(dllimport)
#   endif
#else
#       define MY_LIB_API
#endif

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

and in a .cpp-file from the selected dynamic library:

template<> int A<SpecificType1>::x = 0;
template<> int A<SpecificType2>::x = 0;
…

But unfortunately, this way does not work with linux/clang, where in other .cpp-files I get:

error: instantiation of variable 'A<SpecificType1>::x' required here, but no definition is available

Is there a universal way for solving my task?

Upvotes: 2

Views: 152

Answers (1)

Jan Gabriel
Jan Gabriel

Reputation: 1206

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.

Upvotes: 2

Related Questions