关于模板函数只能在头文件中实现这件事

最近在实现一个序列化功能,大致如下:

// seialize.h
#pragma once

#include <vector>
#include <type_traits>

class Serializer
{
public:
  template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
  bool serialize(const T &data);

private:
  std::vector<char> _buffer;
};
// serialize.cc
#include "traits.h"
#include <iostream>

template <typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>
bool Serializer::serialize(const T &data)
{
  std::cout << "serialize is_floating_point..." << std::endl;
  return false;
}
// main.cc
#include "traits.h"
#include <iostream>

int main()
{
  Serializer s;
  float f;
  s.serialize(f);

  double d;
  s.serialize(d);
  return 0;
}

然后,编译,报错:

g++ -std=c++11 main.cc serialize.cc 
/tmp/cc6mdxGl.o: In function `main':
main.cc:(.text+0x33): undefined reference to `bool Serializer::serialize<float, float>(float const&)'
main.cc:(.text+0x46): undefined reference to `bool Serializer::serialize<double, double>(double const&)'
collect2: error: ld returned 1 exit status

嗯,链接失败。但是,如果我们将serialize.cc中的实现放到serialize.h中,则可以编译通过,正常调用。为什么呢?这涉及到一个广为人知的规则——模板函数只能在头文件中实现。下面这篇文章从编译的角度解释原因——关于模板类的函数定义只能写在头文件这事