c++templatesnamespacesexplicit-instantiationtranslation-unit

Prevent C++ template codes from being compiled for many times


I coded a message queue template in c++, and I want use it in many different projects, so that I put it into a namespace, for example my_lib.

In order to prevent the codes from being compiled repeatedly, I used a separate trans-unit to explicitly instantiate it (and get only one obj file), and merely include its header every where involving it.

But where it being used, is in another namespace for example business.

The skeleton of my codes looks like the followings:

mq-template.hpp:

#pragma once
namespace my_lib {
template<typename T, typename SIZE_TYPE>
class GenericMQ_t {
    struct Node_t {
        SIZE_TYPE _head;
        SIZE_TYPE _tail;
        T         _data;
    };
    SIZE_TYPE _size {};
    Node_t*   _buff {};
public:
    void send( const T& );
};
}; // namespace my_lib

mq-template.tpp (mind the suffix):

#include "mq-template.hpp"
namespace my_lib {
template<typename T, typename SIZE_TYPE>
void GenericMQ_t<T, SIZE_TYPE>::send( const T& ) {
    // just for example
    std::cout << "Hello!";
};
}; // namespace my_lib

mq-instance.hpp:

#pragma once
#include "mq-template.hpp"
namespace business {
struct Msg_t {};
using RealMQ_t = my_lib::GenericMQ_t<Msg_t, int>;
}; // namespace business

mq-instance.cpp:

#include "mq-instance.hpp"
#include "mq-template.tpp"
namespace business {
template class my_lib::GenericMQ_t<Msg_t, int>;
}; // namespace business

main.cpp:

#include "mq-instance.hpp"
int main() {
    business::Msg_t    msg;
    business::RealMQ_t mq;
    mq.send( msg );
    return 0;
}

When mq-instance.cpp was compiling, I got some error like this:

explicit instantiation of 'class my_lib::GenericMQ_t<business::Msg_t, int>' in namespace 'business' (which does not enclose namespace 'my_lib') [-fpermissive]

explicit instantiation of 'struct my_lib::GenericMQ_t<business::Msg_t, int>::Node_t' in namespace 'business' (which does not enclose namespace 'my_lib') [-fpermissive]

It is impossible to put my all codes into a same namespace, because they belongs to different projects, and even though in a same project, the naming schema may be hierarchical.

How should I modify my code, let it satisfy both of:

  1. The template codes should not be compiled for many times;
  2. The template codes and instantiating codes may sit in different namespaces;

Solution

  • You can move the explicit instantiation to the enclosing namespace(which is global namespace) as shown below.

    mq-instance.cpp

    #include "mq-instance.hpp"
    #include "mq-template.tpp"
    
    template class my_lib::GenericMQ_t<business::Msg_t, int>; //in global namespace
    namespace business {  
    
    };
    
    

    Working demo