Search code examples
c++templatesexplicit-instantiation

explicitly instantiate a function template with a generic type


I don't have much experience with C++ template so my terminology might be off. Please bear with me and correction is welcome.

I have generic type fixed_buf<N>:

// in foo.h
template <int N>
class fixed_buf {
 private:
  unsigned char data[N];
 public:
  const unsigned char* begin() const {
    return std::begin(data);
  }

  const unsigned char* end() const {
    return std::end(data);
  }
};

And I want to define a generic to_hex function

// in foo.h
template <typename T> std::string to_hex(const T& b);

// in foo.cpp
template <typename T> string to_hex(const T& b) {
  string r;
  hex(b.begin(), b.end(), back_inserter(r));
  return r;
}

Using explicit instantiation I have following as well:

// in foo.cpp
template string to_hex(const vector<unsign char>&);

How should I explicitly instantiate to_hex with fixed_buf<N>? Is it possible?


Solution

  • "explicitly instantiate"

    This means to tell the compiler to create a function from the function template with some specified types, even if it might not be needed (e.g. to be able to link against it or to reduce compile times).

    A template can be seen as a "type level function". Your to_hex takes some type as argument and "returns" a function of some type.

    to_hex :: T -> to_hex<T>
    

    Your fixed_buf is also a type level function. It takes some (compile time type level) integer and returns a (structure) type:

    fixed_buf :: int(N) -> fixed_buf<N>
    

    You cannot "pass" fixed_buf to to_hex; it's not a type but a type level function. You can only pass the result of fixed_buf. If You don't know what (type level) integer to pass to fixed_buf then you need to turn this into a (type level) function:

    \N -》 to_hex(fixed_buf(N)) :: int(N) -> to_hex<fixed_buf<N>>
    

    Without some specified type level integer this is not a type though; and only types (= completely applied templates in this case) can be instantiated by the compiler.

    So you can explicitly instantiate to_hex<fixed_buf<42>> (this is one function) but not to_hex<fixed_buf<N>> (a template).

    You can explicitly instantiate to_hex<fixed_buf<1>>, to_hex<fixed_buf<2>>, ... though; but I don't think that it would be reasonable to do so


    If you don't mean instantiate but rather "specialise" then again no, you cannot provide a template specialisation because it would need to be a partial specialization (you don't know N) and these are not allowed for functions. Solutions:

    • put the implementation into a template struct; they can be partially specialised.

    • Use an overload:

      template <int N>
      string to_hex(const fixed_buf<N>& b) { /* implementation */ }
      

      This is an overload (not a partial specialisation; these are not allowed for function templates) which should work.