I'm surprised to not have found an answer to my question here already. If I overlooked it feel free to point me there.
Edit: I got a notification that this could be a possible duplicate of Why can templates only be implemented in the header file? While this contains a lot of helpful information on how classes templated classes are treated by the compiler I still don't find information on how to treat static constant members needed by the class that are actually only needed once for all possible template instantiations.
My use-case is a templated floating point number to string conversion class. One member function should be a function that creates numbers appended with si-prefixes. Therefore some lookup array with the prefix characters is needed - this array is unrelated to whichever templated floating point type is actually chosen. I did something like that:
// Float2String.h
#include <string>
template <typename FloatType>
class Float2String
{
public:
//...
static std::string withSIPrefix (FloatType floatNumber, int numSignificantDigits)
{
// scale the number, convert it to a string and compute the idx to pick the right prefix...
return floatNumberScaledAndConvertedToString + siPrefixes[idx];
}
private:
static constexpr char[11][3] siPrefixes = {"f", "p", "n", "μ", "m", "", "k", "M", "G", "T", "P"};
};
// Float2String.cpp
#include "Float2String.h"
template <typename FloatType>
constexpr char Float2String<FloatType>::siPrefixes[11][3];
When trying to actually use it e.g. to convert a double number, I get the following linker error:
Error:Undefined symbol 'Float2String<double>::siPrefixes' referenced from:
Error: Float2String<double>::withSIPrefix(double, int) in Main.o
I'm on Mac OS with Clang and compile with C++ 14 enabled.
Questions: How do I do it right? And maybe could this be done better with a different approach?