7

I have the following template method:

struct MyStruct
{
  // ...
  template<typename T>
  void readField(std::istream& in, T& data)
  {
      read(in, data);
      data = ntohl(data);
  }
};

template<>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}

But I get those strange linker errors:

/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:62: multiple definition of `void MyStruct::readField(std::basic_istream >&, unsigned char&)' ../Lib/obj/MyStruct.o:/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../include/c++/4.4.7/exception:62: first defined here collect2: ld returned 1 exit status make: *** [Lib] Error 1

How can I specialize this member function?

EDIT

This approach works:

struct MyStruct
{
  // ...
  template<typename T>
  void readField(std::istream& in, T& data)
  {
    read(in, data);
    data = ntohl(data);
  }

  void readField(std::istream& in, uint8_t& data)
  {
    read(in, data);
  } 
};

or with inlines or specializing it outside the class with inline

struct MyStruct
{
  // ...
  template<typename T>
  void readField(std::istream& in, T& data)
  {
      read(in, data);
      data = ntohl(data);
  }
};

template<>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • 5
    Function specialization is a regular function, not a template. As any other function, it must be declared in a header file and implemented in a source file; or else, implemented in a header file but marked `inline`. – Igor Tandetnik Jan 26 '16 at 15:23
  • @IgorTandetnik This approach works. You can submit it as an answer and I can accept it. Although I can define this method in the header file without `inline`. Why is that so? – Patryk Jan 26 '16 at 15:38
  • `I can define this method in the header file without inline` Clearly you cannot, or you woudln't be here asking questions. You get a linker error when you try, don't you? Perhaps I misunderstand what you are trying to say. – Igor Tandetnik Jan 26 '16 at 15:40
  • @IgorTandetnik Ok so what I meant was that I can define the method (without any templates/specialization) in the header file inside the class without `inline`. What I can do is as you mentioned specialize it with `inline` but only outside the class definition. Thanks a lot – Patryk Jan 26 '16 at 15:48
  • 3
    An in-class definition of a member function is implicitly `inline`. – Igor Tandetnik Jan 26 '16 at 15:49
  • @IgorTandetnik That I didn't know! :) – Patryk Jan 26 '16 at 15:50
  • @Igor, Patryk is saying (I think) that the specialization is not within the struct MyStruct, but still in the same header file. I just tried this an it compiled without error. I will update answer below. – RobClucas Jan 26 '16 at 15:51
  • @Patryk I tested in the header file, but without inline, and no errors. – RobClucas Jan 26 '16 at 16:07
  • @nabla Make a project that consists of at least two source files that both include that header. If you only include it once, then you only have one definition, and no conflict. The problem is not "the function definition is in header file" per se - it's rather "the function is defined more than once in a program". See also http://en.cppreference.com/w/cpp/language/definition , and in particular "One Definition Rule" section thereof. – Igor Tandetnik Jan 26 '16 at 17:06
  • @IgorTandetnik you're right, forgot about that! – RobClucas Jan 26 '16 at 17:11

2 Answers2

11

As Igor mentioned, you can implement the generic version in the header file, and then the specialization in the cpp file, for example:

// MyStruct.h

struct MyStruct {
  // ...
  template <typename T>
  void readField(std::istream& in, T& data) {
    read(in, data);
    data = ntohl(data);
  }
};

Then in the cpp file you can implement the specialization, for example:

// MyStruct.cpp

template <>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data) {
  read(in, data);
}

Update: After reading the comments, the specialization can also be in the same header file as the primary template, but not within the struct, for example (I verified this by compiling and running a similar example without error):

// MyStruct.h

struct MyStruct {
  // ...
  template <typename T>
  void readField(std::istream& in, T& data) {
    read(in, data);
    data = ntohl(data);
  }
};  

template <>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data) {
  read(in, data);
}

// End MyStruct.h
RobClucas
  • 815
  • 7
  • 16
  • 1
    When implementing the specialization in the source file, you need to declare it in the header. As in `template <> void MyStruct::readField(std::istream& in, uint8_t& data);` The calling code needs to know that the specialization exists, even if it doesn't need to see its actual implementation. – Igor Tandetnik Jan 26 '16 at 22:49
3

You can inline the specialization to avoid multiple definitions.

template<>
inline void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}

Just to be complete, the other option you have is to create an implementation in the .cpp file, and export the implementation through the header.

//MyStruct.h

#ifdef MYSTRUCT_EXPORTS
#ifdef __GNUC__
#ifndef __linux__
#define MYSTRUCT_API __attribute__ ((dllexport))
#else
#define MYSTRUCT_API __attribute__ ((visibility ("default")))
#endif
#else
#define MYSTRUCT_API __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#ifndef __linux__
#define MYSTRUCT_API __attribute__ ((dllimport))
#else
#define MYSTRUCT_API __attribute__ ((visibility ("default")))
#endif
#else
#define MYSTRUCT_API __declspec(dllimport)
#endif
#endif

template<>
void MYSTRUCT_API MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data);


//MyStruct.cpp

template<>
void MyStruct::readField<uint8_t>(std::istream& in, uint8_t& data)
{
    read(in, data);
}
Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
  • This works :) but we must remember that it only works with specialization outside the class definition – Patryk Jan 26 '16 at 15:49
  • @Patryk yea, I've added an example for how to export an implementation, which would work for specializations inside the class definition as well. – Yochai Timmer Jan 26 '16 at 16:12