Alternative to "extern pattern" in each source file

I am working on a library where many of our main objects are templates with one specific instance that appears in most project files as a smart pointer to this template instance. I explicitly create these templates in a single source file. We recently switched to C ++ 11, and I'm trying to use a new

extern template class MyTemplate<double>;

to speed up compilation. My first question is: can my use of smart pointers around

MyTemplate<double>

implicitly creates an instance of the template and requires an "extern template .." at the top of the file to avoid duplication of the instance.

My second question is: is there an alternative to adding all of these

extern template class MyTemplate<double>;

for each source file. It just gets a little tedious grepping each instance of a smart pointer for every template that I define, and make sure I have the correct "extern template" line in this file. I also see that it was a little difficult to enforce this agreement for future developers of our code, because they can add an instance of the template and forget the corresponding extern template line, especially since no error will be generated.

+4
source share
3 answers

, , ( extern template), .

, — , ( extern) (extern ). ++ 14 14.7.2/11; ++ 11.

+4

extern template , template. :

useful.hxx:

#ifndef USEFUL_HXX
#define USEFUL_HXX

namespace my
{

  template <typename T>
  T
  do_useful_stuff(T x)
  {
    return x;
  }

  extern template int   do_useful_stuff(int);
  extern template float do_useful_stuff(float);
  // Potentially many more...

}  // namespace my

#endif  // ifndef USEFUL_HXX

useful.cxx:

#include "useful.hxx"

namespace my
{

  template int   do_useful_stuff(int);
  template float do_useful_stuff(float);
  // Potentially many more...

}  // namspace my

, , main.cxx:

#include <iostream>
#include "useful.hxx"

int
main()
{
  std::cout << my::do_useful_stuff(42) << std::endl;
  std::cout << my::do_useful_stuff(1.0f) << std::endl;
}

useful.cxx main.cxx, .

. , , . , useful.txx

#ifndef MY_EXTERN
#error "Please '#define MY_EXTERN' to 'extern' or '' before '#include'ing this file."
#endif

namespace my
{

  MY_EXTERN template int   do_useful_stuff(int);
  MY_EXTERN template float do_useful_stuff(float);
  // Potentially many more...

}  // namspace my

#include useful.cxx

#include "useful.hxx"

#define MY_EXTERN /* empty*/
#include "useful.txx"
#undef MY_EXTERN

useful.hxx

#ifndef USEFUL_HXX
#define USEFUL_HXX

#ifndef MY_USE_EXTERN_TEMPLATES
#define MY_USE_EXTERN_TEMPLATES 0
#endif

namespace my
{

  template <typename T>
  T
  do_useful_stuff(T x)
  {
    return x;
  }

}  // namespace my

#if MY_USE_EXTERN_TEMPLATES
#define MY_EXTERN extern
#include "useful.txx"
#undef MY_EXTERN
#endif

#endif  // ifndef USEFUL_HXX

. , extern , . main.cxx:

#define MY_USE_EXTERN_TEMPLATES 1

#include <iostream>
#include "useful.hxx"

int
main()
{
  std::cout << my::do_useful_stuff(42) << std::endl;
  std::cout << my::do_useful_stuff(1.0f) << std::endl;
}

useful.cxx main.cxx . #define MY_USE_EXTERN_TEMPLATES 1 main.cxx, .

+2

, , extern, , .

, extern, , . , . , , T ( varadic is_same?):

// Template header
#include <string>
#include <vector>

template<typename T, typename... Rest>
struct is_any : std::false_type {};

template<typename T, typename First>
struct is_any<T, First> : std::is_same<T, First> {};

template<typename T, typename First, typename... Rest>
struct is_any<T, First, Rest...>
    : std::integral_constant<bool, std::is_same<T, First>::value || is_any<T, Rest...>::value>
{};

template<typename T>
class MyT {
public:
  MyT(); // must not be inline, otherwise no extern magic happens
};

extern template class MyT<double>;
extern template class MyT<std::string>;

// Somwhere in the app code
int main()
{
    //MyT<int> dd1;         // error
    MyT<std::string> dd2; // ok
    MyT<double> dd3;      // ok
}

// Template implementation file
template<typename T>
  MyT<T>::MyT() {
    static_assert(is_any<T, double, std::string>::value, "ups... you forgot to make it extern template!"); 
  }

template class MyT<double>;
template class MyT<std::string>;
0

Source: https://habr.com/ru/post/1584315/


All Articles