0

I am having an issue getting template specialization of member methods to compile correctly. I have read all the suggested articles and, in every one, the class itself is templated. In my case, I don't have a templated class, just simple a templated method.

Here is an example:

//In Test.h
class Test {
public:
    template <typename T>
    void foo(const T& v) {
        //Do something generic with T
    }
};

//In Test.cpp
template <>
void Test::foo<unsigned int>(const unsigned int& v) {
    //Do something specific with unsigned int
}

Based upon this article multiple definition of template specialization when using different objects I have put the specializations in my CPP file. However, this results in the specialized function NOT being called when I do something like the following:

#include "Test.h"

int main() {
    Test t;
    unsigned int a;
    
    t.foo(a);
}

However, If I put the specializations in the .h file, then I get a ton of "duplicate definitions of" errors.

What is the correct way to go about this?

Thanks!

EDIT

Here is a snippet of my actual code

#ifndef BYTEARRAY_H_
#define BYTEARRAY_H_

#include <memory>
#include <limits.h>
#include <string.h>
#include <iterator>

namespace tw {

class ByteArray {
public:
    //...

    size_t append(const void* source, size_t sourceSize);

    template <typename T>
    inline size_t append(const T& v) {
        static_assert(std::is_trivially_copyable<T>::value, "T must be trivially copyable (i.e. via memcpy) to use ByteArray::append<T>");

        return append(reinterpret_cast<const void*>(&v), sizeof(T));
    }

private:
    void _deepCopy();

    //-- Member Data --
    /**
     * @brief Total number of bytes allocated and pointed to by _memory
     */
    size_t _capacity;

    /**
     * @brief Current "virtual" size of the array
     */
    struct {
        size_t _length : (CHAR_BIT * sizeof(size_t)) - 1;
        bool _isStatic : 1;
    };

    /**
     * @brief Shared/smart pointer to the underlying, allocated array of bytes
     */
    std::shared_ptr<uint8_t[]> _memory;

    /**
     * @brief A small amount of memory for use when capacity() < sizeof(size_t)
     *        rather than allocated memory on the heap for _memory
     */
    uint8_t _memoryDirect[sizeof(size_t)];
};

template <>
size_t ByteArray::append<ByteArray>(const ByteArray& v) {
    return append(v.data().get(), v.length());
}

template <>
size_t ByteArray::append<uint8_t>(const uint8_t& v) {
    ASSERT(!isFull());

    dataMutable().get()[_length++] = v;

    return 1;
}

} /* namespace tw */

#endif /* BYTEARRAY_H_ */
Patrick Wright
  • 1,401
  • 7
  • 13

1 Answers1

1

Thanks to @Jarod42 for his comment. My issue was that my original template was specified as inlined, however, when I added my specializations, they were no longer implicitly inlined.

For reference, this is all I have to change:

template <>
inline size_t ByteArray::append<ByteArray>(const ByteArray& v) {
    return append(v.data().get(), v.length());
}
Patrick Wright
  • 1,401
  • 7
  • 13