Reputation: 24092
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 inline
s 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);
}
Upvotes: 10
Views: 14386
Reputation: 845
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
Upvotes: 14
Reputation: 49221
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);
}
Upvotes: 4