Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Good design for delegating template-member functionality

I am having trouble in finding simple and elegant design for the following scenario. Class Worker uses template class Helper to do some work. In the simple scenario it looks like this:

template<typename T>
class Helper {
  public:
    void Help(T data) : m_data(data) {} //NOTICE: Copy
    T const& Data() const { return m_data; }

    T m_data;
}

class SimpleWorker {
  public:
    SimpleWorker() : m_helper(SimpleData()) {} // non-temp used in reality
    void DoWork()
    {
        m_helper.help();
    }        

    Helper<SimpleData> m_helper;
}

Things get complicated for me when the template argument is more complex and is of the same business domain of the worker. The worker needs to use the helper but it would also need to call some methods on the data object that the helper doesn't even know about (in this design). Something like:

template<typename T>
class Helper {
  public:
    Helper(T data) : m_data(data) {} //NOTICE: Copy
    T const& Data() const { return m_data; }

    T m_data;
}

class ComplexWorker {
  public:
    ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality

    void DoWork()
    {
        m_helper.help();
        m_helper.GetData().DoSomethingComplexNotConst(); // <-------------
    }    

    Helper<ComplexData> m_helper;    
}

The obvious problem is that I can't call not const function on Data() result. Making Data() non-const seems like a bad idea as Helper is used in different contexts as well. My goal is to find an elegant way to alter ComplexData using its member functions from ComplexWorker The ComplexData needs to be altered in the first place so that Helper can continue working with the altered data.

EDIT: Changed Helper construction to copy the provided data to better resemble actual flow

like image 869
Xyand Avatar asked Jan 25 '26 12:01

Xyand


1 Answers

I think it's best to let Helper have only static functions, not maintaing state (as you create temporary ComplexData() in ComplexWorker in your own code). Pass the data by reference or const-reference depending on whether you need to modify or not.

// primary template
template<typename T>
class Helper {
public:
    static void help(T const& data) const {} // non-modifying
};

// specialization for ComplexData
template<>
class Helper<ComplexData> {
public:
    static void help(ComplexData const& data) const { } // non-modifying

    static void DoSomethingComplexNotConst(ComplexData& data) // modifying
    {
         // your implementation here
    }
};

class ComplexWorker {
public: 
    ComplexWorker() : m_data(ComplexData()) {} // create new data

    void DoWork()
    {
        Helper<ComplexData>::help(m_data);
        Helper<ComplexData>::DoSomethingComplexNotConst(m_data); // <--- now no problem
    }

   private:
       ComplexData m_data;         
};

Note that I made a template specialization for the ComplexData. There is some code duplication in help() but you can easily extract this into a common non-member helper function.

like image 89
TemplateRex Avatar answered Jan 28 '26 04:01

TemplateRex



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!