0

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?

4
  • 1
    Possible duplicate of Why can templates only be implemented in the header file? Commented Sep 25, 2018 at 8:15
  • Why do you need to define anything in the .cpp file at all? godbolt.org/z/MLUmDm Commented Sep 25, 2018 at 8:58
  • @Evg while your code snippet compiles fine on godbolt it still throws the same linker error on my machine when trying to compile the very same code in a simple command line project containing just one source file. I am used that static members need to be defined in a separate compile unit, this is why I put them into a separate .cpp file Commented Sep 25, 2018 at 9:17
  • You could put your static member variable inside a static method that just returns it. Commented Sep 25, 2018 at 10:05

1 Answer 1

2

Perhaps you can define your siPrefixes outside the template calss. It does not depend on your template type.

You can define it directly in your cpp file and move method withSIPrefix implementation in your cpp file also.

Sign up to request clarification or add additional context in comments.

2 Comments

could you elaborate how you would actually implement this solution with a short code example?
Forget about the second part of my answer. Just transfer your code from the Float2Type.cc to Float2Type.h (this code: template <typename FloatType> constexpr char Float2String<FloatType>::siPrefixes[11][3];) If you want to keep your code in .cc file you have to instanciate explicitly your siPrefix attribute for every template you will use. This is why I will export it to the .h file, and even, if you don't care about the siPrefix to be private, take this variable outside the class

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.