1

Consider this code:

rgb.h

namespace Company{
namespace Core{
constexpr int RGB_MIN = 0;
constexpr int RGB_MAX = 255;

template<typename T>
class RGB;

using RGBi = RGB<int>;

template<typename T>
class RGB
{
public:
   constexpr RGB() : R(0), G(0), B(0)
   {
   }

   constexpr RGB(T red, T green, T blue) : R(red), G(green), B(blue)
   {
   }

   static constexpr RGB<T> Red   = RGB<int>(RGB_MAX,RGB_MIN,RGB_MIN);
   static constexpr RGB<T> Green  = RGB<int>(RGB_MIN,RGB_MAX,RGB_MIN);
   static constexpr RGB<T> Blue = RGB<int>(RGB_MIN,RGB_MIN,RGB_MAX);

   operator std::string() const
   {
      std::ostringstream s;
      s << "RGB=" << R << "," << G << "," << B;
      return s.str();
   }
   T R, G, B;
};

template<class T>
std::ostream& operator<<(std::ostream & os, const RGB<T>& rgb)
{
    return os << rgb;
}

}
}

qt_addons.h

#include <QDebug>
QDebug operator <<(QDebug debug, const std::string& object)
{
   debug << QString::fromStdString(object);

   return debug;
}

main.cpp

#include <iostream>
#include "qt_addons.h"
#include "rgb.h"
int main()
{
   using namespace Company::Core;

   qDebug() << RGBi::Blue;

   return 0;
}

Everything works perfectly, but if I try to use a std::cout instead of a qDebug, it gives me an

'undefined reference to Company::Core::RGB::Blue'

If I try to initialize a normal variable it still works with qDdebug(), but it goes to segmentation fault with std::cout.

What am I missing?

SOLVED:

There was two problems: declaring the static variable and the operator<< method. This fixed the issue.

operator std::string() const
   {
      return toString();
   }

   std::string toString() const
   {
      std::ostringstream s;
      s << "RGB=" << R << "," << G << "," << B;
      return s.str();
   }

and outside:

template<typename T>
constexpr RGB<T> RGB<T>::Red;

template<typename T>
constexpr RGB<T> RGB<T>::Green;

template<typename T>
constexpr RGB<T> RGB<T>::Blue;

template<class T>
std::ostream& operator<<(std::ostream & os, const RGB<T>& rgb)
{
    return os << rgb.toString();
}
Moia
  • 2,216
  • 1
  • 12
  • 34
  • Try moving `RGBi` declaration after template class definition. – user7860670 Apr 17 '18 at 14:57
  • You'll need to add a definition for your `static` members after your template definition. See [this question](https://stackoverflow.com/questions/20642103/undefined-reference-to-static-member-of-template-class-accessed-from-static-me). – François Andrieux Apr 17 '18 at 14:59
  • @FrançoisAndrieux could you please explain it better? – Moia Apr 17 '18 at 15:02
  • Also `operator<<` calls itself recursively. And there is no need to add definitions for `constexpr` static members starting from c++17. – user7860670 Apr 17 '18 at 15:03
  • As @VTT mentioned the `operator<<` function performs infinite recursion. Look at your stack trace is it seg faulting because of a stack overflow? Did you intend to force the implementation of `operator<<` to use the `operator std::string` conversion function? – James Adkison Apr 17 '18 at 15:08
  • @Moia The linked question explains it pretty well. – François Andrieux Apr 17 '18 at 15:09
  • @FrançoisAndrieux if not defined it would give me error with qDebug() too, isn't it? – Moia Apr 17 '18 at 15:10
  • @JamesAdkison yes, though was not the correct implementation itself. I was trying that for using cout with a template class – Moia Apr 17 '18 at 15:13
  • @FrançoisAndrieux if i add `template constexpr RGB RGB::Blue = RGB(RGB_MIN,RGB_MIN,RGB_MAX);` after the class definition it gives me already defined error. If I remove the initialization it gives "static member must have an initializer. – Moia Apr 17 '18 at 15:25
  • @Moia Edit your question with this new information. – François Andrieux Apr 17 '18 at 15:28
  • @Moia It sounds like you may have move the initialization to the member definition. Leave it at the declaration (in the class definition) and don't provide an initializer at the definition (after the class definition). – François Andrieux Apr 17 '18 at 15:30

0 Answers0