0

I have an implementation of a class template with a base class.

class MyBase
{
protected:
    virtual void getErrorPercent(std::ostream& fileStream) = 0;
    virtual void getFormattedText(std::ostream& fileStream) = 0;
};

template <class T>
class MyClass : public MyBase
{
protected:
    void getErrorPercent(std::ostream& fileStream) override
    void getFormattedText(std::ostream& fileStream) override
private:
    std::string getErrorPercentageStr();
    T m_expected;
    T m_measured;
};

In cpp [moved from in class]:

template <class T>
std::string MyClass<T>::getErrorPercentageStr()
{
    return "";
}

template <class T>
void MyClass<T>::getErrorPercent(std::ostream& fileStream)
{
    // Default for any type is to do nothing
}

template <class T>
void MyClass<T>::getFormattedText(std::ostream& fileStream)
{
    fileStream << "Measured " << m_measured << ", Expected " << m_expected;
}

I want to add function template specialisation for getErrorPercent, getFotmattedText and getErrorPercentageStr for double types only.

For getErrorPercent I want to:

template<>
void MyClass<double>::getErrorPercent(std::ostream& fileStream)
{
   fileStream << " Error " << getErrorPercentageStr() << std::endl;
}

For getFotmattedText I want to:

template<>
void MyClass<double>::getFormattedText(std::ostream& fileStream)
{
   fileStream << "Measured " << m_measured << ", Expected " << m_expected
       << " [Error " << getErrorPercentageStr() << "]";
}

The getErrorPercentageStr function for double will calculate the error [m_measured and m_expected will be doubles] and return it as a string. For all other types it will return an empty string.

template<>
std::string MyClass<double>::getErrorPercentageStr();
{
    std::ostringstream rep;
    double difference = m_measured - m_expected;
    if (m_expected == 0.0)
    {
        rep << difference << "V";
    }
    else
    {
        double error = (difference / m_expected) * 100.0;
        if (std::abs(error) < 100.0)
        {
            rep << error << "%";
        }
        else
        {
            rep << difference << "V";
        }
    }
    return rep.str();
}

I have been searching for a solution but can't get it to either compile or call the correct function for double.

How/where do I put specialised versions of the functions? I don't think I can put these in the class itself.

In the h or cpp file?

Can I leave the main implementations of the functions [non specialised] in the class?

Do i need to put prototypes somewhere for the specialised functions?

template<> std::string MyClass<double>::getErrorPercentageStr();
template<> void MyClass<double>::getErrorPercent(std::ostream& fileStream);
template<> void MyClass<double>::getFormattedText(std::ostream& fileStream);

And then implement in cpp?

I tried this and get lots of "unresolved external symbol" for int versions of MyClass::getFormattedText() and MyClass::getErrorPercent(). Also for bool, unsigned int and std::basic_string versions too. All these should use the default version.

How do I fix these?

I did get it working with "if constexpr (std::is_same_v<T, double>)" to process it but this failed to compile with vxWorks. Complained about << for double in getErrorPercentageStr where "rep << difference << "V";".

error: no match for 'operator<<' (operand types are 'std::ostringstream' and 'double')

Any help would be greatly appreciated!

Diz
  • 1
  • If all the compiler ever sees when encountering a instanciation of the template is the class declaration, the functions will never get compiled. Where you want to put the implementation basically depends on how you want to use the class. Do you want implicit initializations of the class to be sufficient? Then the implementation should be available in the header. Do you want to explicitly instanciate the template in the cpp file for all the template parameters used in your project? Then you can keep it in the cpp file. Regardless the compiler needs to know about the specializations in the head – fabian Feb 04 '22 at 21:27
  • @fabian Where do I put the prototype in the header then [above class or below] - template<> void SelfTestResult::onGetErrorPercent(std::ostream& fileStream); Put template void SelfTestResult::onGetErrorPercent(std::ostream& fileStream); too? – Diz Feb 04 '22 at 21:47

0 Answers0