Force definition of symbol for a C++ template instance in a library

前端 未结 3 800
抹茶落季
抹茶落季 2021-01-19 12:21

I\'d like to provide a library that provides template code. But I would also like to keep the most possible the ownership of this code (generated code) when I can guess the

相关标签:
3条回答
  • 2021-01-19 12:48

    I would separate the implementation and the interface, using template specialization:

    lib1.h:

    #include <iostream>
    template <int T> void print_me(void);
    template <> void print_me<0>(void);
    template <> void print_me<1>(void);
    

    lib1_internal.h (NOTE: this does not need to be disclosed):

    #include <iostream>
    
    template<int N>
    void print_me_internal() {
        std::cout << "I am function number " << N << std::endl;
    }
    

    lib1.cpp:

    #include "lib1.h"
    #include "lib1_internal.h"
    
    template <> void print_me<0>() {
      print_me_internal<0>();
    }
    template <> void print_me<1>() {
      print_me_internal<1>();
    }
    

    your main.cpp will correctly lead to a linker error:

    $ g++ main.cpp -L. -l1
    /tmp/ccZSDqkp.o: In function `main':
    main.cpp:(.text+0xf): undefined reference to `void print_me<2>()'
    collect2: ld returned 1 exit status
    

    Just add the definition of template <int T> void print_me(void) in lib1.h in place of its declaration and it will be used whenever not found in the specialized versions.

    0 讨论(0)
  • 2021-01-19 12:50

    You have to hide the implementation in the header file.

    //lib1.h    
    template<int N>
    void print_me();
    
    //lib1.cpp
    #include <iostream>
    #include "lib1.h"
    template <int printme>
    void print_me()
    {
      std::cout << printme << std::endl;
    }
    
    template void print_me<0>();
    template void print_me<1>();
    

    What is happening is how templates are typically used: they are only built when needed (else you'd have to build a print_me for all integers), so they figure out the implementation when the software runs (which is why it slows down compilation time so much, it rebuilds the class for every compilation unit that uses the template). As long as you have the definition of the template, you can build it for whatever argument you need. This is one of the few cases where hiding the definition in the .cpp file is semi valid, but the end user will typically get one hell of a useless error for print_me<2>(). It'd be better (imho) to use this framework (C++11):

    //lib1.h
    #include <type_traits>
    template<int N>
    typename std::enable_if<N == 1 || N == 0>::type print_me();
    
    //lib1.cpp
    #include <iostream>
    #include "lib1.h"
    
    template<int N>
    typename std::enable_if<N == 1 || N == 0>::type print_me()
    {
      std::cout << N << std::endl;
    }
    
    template void print_me<0>();
    template void print_me<1>();
    

    now the error is "no matching function for call to print_me()" which is a little better...you could do a nested function with a static_assert to make it even better.

    0 讨论(0)
  • 2021-01-19 13:14

    C++11 solution: use extern templates. Simply add these strings to your main.cpp file:

    extern template void print_me<0>();
    extern template void print_me<1>();
    

    Thus you tell compiler not to instantiate print_me function template in main.cpp (for template arguments 0 and 1). So linker should search definition of void print_me<0>(); and void print_me<1>(); in other translation units.

    0 讨论(0)
提交回复
热议问题