darklord
darklord

Reputation: 3

Linker Error in template specialization of a class

This is my header file TimeSeries.h, followed by main.cpp

    template<typename>
            struct default_value;    
            template<>
            struct default_value<int> {
               static constexpr int value = 0;
            };

            template<>
            struct default_value<double> {
               static constexpr double value = std::numeric_limits<double>::quiet_NaN();
            };

            template <typename T>
            class TimeSeries
            {
            public:
               std::vector<uint64_t> timeUsSinceMid;
               std::vector<T> values;

               void addValue(uint64_t time, T value)
                {
                 timeUsSinceMid.push_back(time);
                 values.push_back(value);
                }

               TimeSeries<T> * sample(uint64_t sampleFreq, uint64_t startTime=0, uint64_t 
                 endTime=86400*1000*1000ULL)
                {
                 //Some code
                 // I essentially faked a time and a default value push
                  TimeSeries<T>* newSample = new TimeSeries<T>;
                  newSample->timeUsSinceMid.push_back(timeUsSinceMid[0]);
                  newSample->values.push_back(default_value<T>::value);
                  return newSample;
                }
            };

Here is main.cpp:

#include<TimeSeries.h>
int main(int argc, const char * argv[]) {
    TimeSeries<double> T;
    T.addValue(1, 100.0);
    T.addValue(2,200.0);
    T.addValue(3,300.0);
    T.addValue(4,400.0);
    TimeSeries<double>* newT = T.sample(2,1,6);
    //cout<<*newT<<endl;



    return 0;
}

This is the linker error

Undefined symbols for architecture x86_64:
  "default_value<double>::value", referenced from:
      TimeSeries<double>::sample(unsigned long long, unsigned long long, unsigned long long) in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Can anyone please explain why "default_value::value" is undefined?

Upvotes: 0

Views: 388

Answers (1)

CrepeGoat
CrepeGoat

Reputation: 2515

See the answers for this question.

Using the structure of your posted code

Your template definition defines the object value, but it still needs to be declared. Don't ask me why, I'm just copying @Pete Becker's answer from the other post (which unfortunately wasn't very detailed). All I know is that the below code now compiles:

template<>
struct default_value<double> {
    static constexpr double value = std::numeric_limits<double>::quiet_NaN();
};
// EDIT: inserted line below
constexpr double default_value<double>::value;

Changing the structure a bit

Alternatively, if you don't want to have to track value declarations through a large project, you can also turn the values into in-lined methods, like so: (edit added in constexpr's; also noting that inline is not required & likely doesn't change compiler behavior)

template<>
struct default_value<int> {
    // EDIT: changed value to function
    static inline constexpr int value() {
        return 0;
    }
};

template<>
struct default_value<double> {
    // EDIT: changed value to function
    static inline constexpr double value() {
        return std::numeric_limits<double>::quiet_NaN();
    }
};

Of course, remember to change your TimeSeries::sample method to use default_value<>::value as a method.

Upvotes: 2

Related Questions