Leon
Leon

Reputation: 2077

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;

Upvotes: 0

Views: 141

Answers (3)

Marek R
Marek R

Reputation: 38209

You are making things to complicated. To prevent template instantiation every time it is used you can use this:

extern template my_lib::GenericMQ_t<business::Msg_t, int>;

Then in some cpp file ti enforce instantiation of template you can do:

template my_lib::GenericMQ_t<business::Msg_t, int>;

So first thing you can place below your template definition in mq-template.hpp and second thing in mq-template.cpp. No need to play with other files.

Documentation.

Upvotes: 2

waffentrager
waffentrager

Reputation: 96

I guess it's a pity that you can't move up and down in scopes like you can in Linux, I mean cd ../currentScope and cd currentScope/nextScope but it's interesting that this solution might work in your code.

mq-instance.cpp

namespace my_lib {
    template class GenericMQ_t<::business::Msg_t, int>;
}; // namespace my_lib

Upvotes: 0

Alan
Alan

Reputation: 1

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

Upvotes: 2

Related Questions