Good design for delegating template-member functionality - c++

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

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.

Seems to me that it depends on what Helper is actually doing. Your example just gives a constructor and an accessor but I doubt that is all it does in practice.
Have you considered simply using inheritance? Your Helper template would then look like this:
template<typename T>
class Helper : public T {
Helper(T data) : T(data) {}
void Help() {};
}
In this case you could use the Helper<ComplexData> object directly in an 'is-a' relationship:
class ComplexWorker {
Helper<ComplexData> m_helper;
void DoWork()
{
m_helper.help();
m_helper.DoSomethingComplexNotConst();
}
}

Why not refer to the realization of the Container part in STL. An overload of the Data() function may achieve a ballance between safty and elegance.
template <typename T>
class Helper {
public:
Helper(T data) : m_data(data) {} //NOTICE: Copy
T const& Data() const { return m_data; }
T& Data() {return m_data; }
private:
T m_data;
}
class ComplexWorker {
public:
ComplexWorker() : m_helper(ComplexData()) {} // non-temp used in reality
void DoWork()
{
m_helper.help();
ComplexData &cd1 = m_helper.Data();
cd1.QuerySth();
const ComplexData &cd2 = m_helper.Data();
cd2.ModifySth();
}
private:
Helper<ComplexData> m_helper;
}

Related

Visitor pattern for tree mutation and shared pointer problem

I'm trying to implement visitor pattern for n-ary tree mutation. Currently i'm stuck with shared pointers. Mutator operates on each tree node and can return either pointer to a node itself w/o any changes, or a pointer to a copy of modified node (original node cannot be modified directly). But obviously i can't build a shared pointer from a raw pointer inside Visit method, neither i can't make a shared pointer from this inside a Mutate method. The only idea that comes into my mind, is to create another class which will be holding pointer and pass this class pointer to visitor instead, but perhaps there is a better solution?
// Forward declarations
class ExpressionTreeMutator;
struct BaseExpr;
enum class ExpressionType {
kString,
kInt,
};
using ExprPtr = std::shared_ptr<BaseExpr>;
struct BaseExpr {
explicit BaseExpr(ExpressionType expression_type) : expression_type_(expression_type) {}
virtual ~BaseExpr() = default;
virtual ExprPtr Mutate(ExpressionTreeMutator* visitor) const = 0;
ExpressionType expression_type_;
};
// Curiously recurring template pattern
template<typename T>
struct Expr : public BaseExpr {
explicit Expr(ExpressionType expression_type) : BaseExpr(expression_type) {}
~Expr() override = default;
ExprPtr Mutate(ExpressionTreeMutator* visitor) const override;
};
struct String : public Expr<String> {
explicit String(std::string value) : Expr(ExpressionType::kString),
value_(std::move(value)) {}
std::string value_;
};
struct Int : public Expr<Int> {
explicit Int(int64_t value) : Expr(ExpressionType::kInt),
value_(value) {}
int64_t value_;
};
class ExpressionTreeMutator {
public:
virtual ~ExpressionTreeMutator() = default;
protected:
template<typename T>
friend
struct Expr;
virtual ExprPtr Visit(Int const* expr) {
// return expr ??? (in some cases return ptr as it is)
};
virtual ExprPtr Visit(String const* expr) {
// return String::Make(expr) ??? (make a copy)
};
};
template<typename T>
ExprPtr Expr<T>::Mutate(ExpressionTreeMutator* visitor) const {
return visitor->Visit(dynamic_cast<T const*>(this));
}
As it is tagged C++20, I'd suggest to use std::variant and std::visit instead.
Otherwise, you can inherit from std::enable_shared_from_this, which allows to create shared_ptr from within methods of X.
You can also use mutate not to do the actual mutation, but to return appropriate function object that does the mutation and then pass the shared_ptr to this object.

C++ initialize const member with mutator method

Suppose the following class exists (which I cannot change).
class TheirClass {
public:
TheirClass();
TheirClass(const TheirClass&) = delete;
TheirClass& operator=(const TheirClass&) = delete;
TheirClass(TheirClass&&) = delete;
void FinishInitialization();
}
I would like to use it in my class like so.
class MyClass {
private:
const TheirClass their_class_;
}
If the copy and move constructors were not deleted, I could do something like this.
TheirClass CreateTheirClass() {
TheirClass their_class;
their_class.FinishInitialization();
return their_class;
}
MyClass::MyClass() : their_class_(CreateTheirClass()) {}
Currently my solution is to use pointers.
class MyClass {
private:
const std::unique_ptr<const TheirClass> their_class_;
}
std::unique_ptr<TheirClass> CreateTheirClass() {
auto their_class = std::make_unique<TheirClass>();
their_class->FinishInitialization();
return their_class;
}
MyClass::MyClass() : their_class_(CreateTheirClass()) {}
But this seems to add unnecessary complexity and a needless performance hit (storing the object on the heap rather than the stack).
How can I have a const TheirClass as member in my class while still being able to call TheirClass::FinishInitialization (once, upon initialization of my class)?
You can make a wrapper class that calls FinishInitialization in its constructor, but only exposes the instance as a const.
class TheirClassWrapper final
{
public:
/// The question didn't specify `args`, but I assume you want them here
template <typename... Args>
explicit TheirClassWrapper(Args&&... args)
: impl_()
{
impl_.FinishInitialization(std::forward<Args>(args)...);
}
const TheirClass& operator*() const noexcept { return impl_; }
const TheirClass* operator->() const noexcept { return &impl_; }
private:
TheirClass impl_;
};
Use the wrapper instead:
class MyClass
{
public:
MyClass();
// ...
private:
const TheirClassWrapper their_class_;
}
You then use their_class_->whatever() or *their_class_ to access things. It looks like a pointer, but it will get trivially inlined by your compiler.
A potentially more generic solution to this is:
template <typename T>
class InitWrapper final
{
public:
template <typename FInit>
explicit InitWrapper(FInit&& init)
{
init(impl_);
}
const T& operator*() const noexcept { return impl_; }
const T* operator->() const noexcept { return impl_; }
private:
T impl_;
};
This allows you to run some arbitrary function in the InitWrapper constructor, while still only exposing the const T view of things.
MyClass::MyClass()
: their_class_([](TheirClass& x) { x.FinishInitialization(); })
{ }

Can inhereted classes be made const? [duplicate]

I would like to inherit from a class with the const specifier like this:
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public const Property
{
// Can never call A::set() with this class, even if
// the instantiation of this class is not const
};
class NonConstChild : public Property
{
// Can call both A::set() and A::get() depending on
// the constness of instantiation of this class
};
My compiler obviously gives me an error for the const keyword in the second classes declaration. Ideally I'd like to avoid having to create a new class ReadOnlyProperty from which ConstChild would inherit.
Can I somehow use the const keyword for inheritance?
If not, do you have any other ideas on how to solve this problem?
Introduce mutability later in your inheritance tree and derive appropriately:
class Property
{
int get() const;
};
class MutableProperty : public Property {
{
void set(int a);
};
And then:
class ConstChild : public Property { ... };
class MutableChild : public MutableProperty { ... };
I had the need for a related problem, which is: to really control/highlight mutable and const access on some class.
I did it with this simple reusable template wrapper:
template <typename T>
class TAccessor : private T
{
public:
const T& Const() const { return *this; }
T& Mutable() { return *this; }
};
// Example of use:
template <typename T>
using MyVector = TAccessor<std::vector<T>>;
void main()
{
MyVector<int> vector;
vector.Mutable().push_back(10);
int x = vector.Const()[1];
...
}
If you create a const member function set, you will get what you need.
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public Property
{
void set(int a) const {}
};
The only caveat is that a sly user can circumvent your intention by using:
ConstChild child;
child.set(10); // Not OK by the compiler
Property& base = child;
base.set(10); // OK by the compiler
I would like to inherit from a class with the const specifier"
However much you want to is irrelevant. You cannot. That is not valid C++.
Can I somehow use the const keyword for inheritance?"
No.
Use a data member or private base class instead of public base class.
Then you control the access to that member.
You can make the Property thing an abstract interface if you need polymorphic behavior.
You can use a template class and a specialization for a constant type:
template<typename T> class base_property {
protected:
T value;
};
template<typename T> class property : public base_property<T> {
public:
const T& get()const { return value; }
void set(const T& v){ value = v; }
};
template<typename T> class property<const T> : public base_property<T> {
public:
const T& get()const { return value; }
};
class ConstChild : public property<const int>{ };
I had the same need and I ended up with this quite manual approach :
class A
{
public:
void fooMutable(void) {}
void fooConst(void) const {}
};
class B : private A
{
public:
using A::fooConst;
const A& getParent(void) const
{
return *this;
}
};
void fooParent(const A&) {}
int main(void)
{
auto b = B{};
b.fooConst(); // Ok
b.fooMutable(); // Fail
fooParent(b); // Fail
fooParent(b.getParent()); // Ok
return 0;
}
Note that the using keyword would not work with overloads const/mutable :
class A
{
public:
void foo(void) {}
void foo(void) const {}
};
class B : private A
{
public:
using A::foo; // Expose the const and the mutable version
};
To solve this you could redefine the function yourself and call the parent :
class B : private A
{
public:
void foo(void) const
{
A::foo();
}
};
It can become pretty time consuming if you're inheriting a large hierarchy, but if it's for a not-so-big class it should be very reasonable and being quite natural for the user.
I have a trick, not a clean solution.
class ConstChild : private Property
{
operator const Property () { return *this; }
};
then
ConstChild cc;
cc.set(10); // ERROR
cc().get();

C++ How to get a member from a templated derived class? [duplicate]

I am trying to solve a programming problem that consists of an object (call it Diagram), that contains several parameters. Each parameter (the Parameter class) can be one of several types: int, double, complex, string - to name a few.
So my first instinct was to define my Diagram class as having a vector of template parameters, which would look like this.
class Diagram
{
private:
std::vector<Parameter<T> > v;
};
This doesn't compile, and I understand why. So, based on the recommendations on this page How to declare data members that are objects of any type in a class, I modified my code to look like:
class ParameterBase
{
public:
virtual void setValue() = 0;
virtual ~ParameterBase() { }
};
template <typename T>
class Parameter : public ParameterBase
{
public:
void setValue() // I want this to be
// void setValue(const T & val)
{
// I want this to be
// value = val;
}
private:
T value;
};
class Diagram
{
public:
std::vector<ParameterBase *> v;
int type;
};
I'm having trouble figuring out how to call the setValue function with an appropriate templated parameter. It is not possible to have a templated parameter in the ParameterBase abstract base class. Any help is greatly appreciated.
P.S. I don't have the flexibility to use boost::any.
You got very close. I added a few bits because they're handy
class ParameterBase
{
public:
virtual ~ParameterBase() {}
template<class T> const T& get() const; //to be implimented after Parameter
template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};
template <typename T>
class Parameter : public ParameterBase
{
public:
Parameter(const T& rhs) :value(rhs) {}
const T& get() const {return value;}
void setValue(const T& rhs) {value=rhs;}
private:
T value;
};
//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }
class Diagram
{
public:
std::vector<ParameterBase*> v;
int type;
};
Diagram can then do stuff like these:
Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception
It looks like your intent is to store resource-owning pointers in the vector. If so, be careful to make Diagram have the correct destructor, and make it non-copy-constructable, and non-copy-assignable.
The bellow implementation uses a few C++11 features but you will be
able to pick them apart.
#include <vector>
#include <memory>
class Parameter
{
private:
class ParameterBase {
public:
virtual ~ParameterBase() {}
virtual ParameterBase* copy() = 0;
virtual void foo() = 0;
};
template <typename T>
class ParameterModel : public ParameterBase {
public:
// take by value so we simply move twice, if movable
ParameterModel(const T& t) : t(t) {}
ParameterModel(T&& t) : t(t) {}
void foo() { t.foo(); }
ParameterModel* copy() { return new ParameterModel(*this); }
private:
T t;
};
public:
template <typename T>
Parameter(T&& t)
: pp(new ParameterModel< typename std::remove_reference<T>::type >(std::forward<T>(t))) {}
// Movable and Copyable only
Parameter(Parameter&&) = default;
Parameter& operator=(Parameter&&) = default;
Parameter(const Parameter& other) : pp(other.pp->copy()) {};
Parameter operator=(const Parameter& other) {
pp.reset(other.pp->copy());
return *this;
};
// members
void foo() { pp->foo(); }
private:
std::unique_ptr<ParameterBase> pp;
};
class Diagram
{
public:
std::vector<Parameter> v;
int type;
};
struct X {
void foo() {}
};
struct Y {
void foo() {}
};
int main()
{
Diagram d;
d.v.emplace_back(X()); // int
// parameters are copyable and can be reassigned even with different
// impls
Parameter p = d.v.back();
Parameter other((Y()));
other = p;
return 0;
}
What does this code do? It hides the fact that we use inheritance to
implement parameters from our users. All they should need to know is
that we require a member function called foo. These requirements are
expressed in our ParameterBase. You need to identify these
requirements and add the to ParameterBase. This is basically a more
restrictive boost::any.
It is also quite close to what is described in Sean Parent's value semantics talk.

Inherit from const class

I would like to inherit from a class with the const specifier like this:
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public const Property
{
// Can never call A::set() with this class, even if
// the instantiation of this class is not const
};
class NonConstChild : public Property
{
// Can call both A::set() and A::get() depending on
// the constness of instantiation of this class
};
My compiler obviously gives me an error for the const keyword in the second classes declaration. Ideally I'd like to avoid having to create a new class ReadOnlyProperty from which ConstChild would inherit.
Can I somehow use the const keyword for inheritance?
If not, do you have any other ideas on how to solve this problem?
Introduce mutability later in your inheritance tree and derive appropriately:
class Property
{
int get() const;
};
class MutableProperty : public Property {
{
void set(int a);
};
And then:
class ConstChild : public Property { ... };
class MutableChild : public MutableProperty { ... };
I had the need for a related problem, which is: to really control/highlight mutable and const access on some class.
I did it with this simple reusable template wrapper:
template <typename T>
class TAccessor : private T
{
public:
const T& Const() const { return *this; }
T& Mutable() { return *this; }
};
// Example of use:
template <typename T>
using MyVector = TAccessor<std::vector<T>>;
void main()
{
MyVector<int> vector;
vector.Mutable().push_back(10);
int x = vector.Const()[1];
...
}
If you create a const member function set, you will get what you need.
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public Property
{
void set(int a) const {}
};
The only caveat is that a sly user can circumvent your intention by using:
ConstChild child;
child.set(10); // Not OK by the compiler
Property& base = child;
base.set(10); // OK by the compiler
I would like to inherit from a class with the const specifier"
However much you want to is irrelevant. You cannot. That is not valid C++.
Can I somehow use the const keyword for inheritance?"
No.
Use a data member or private base class instead of public base class.
Then you control the access to that member.
You can make the Property thing an abstract interface if you need polymorphic behavior.
You can use a template class and a specialization for a constant type:
template<typename T> class base_property {
protected:
T value;
};
template<typename T> class property : public base_property<T> {
public:
const T& get()const { return value; }
void set(const T& v){ value = v; }
};
template<typename T> class property<const T> : public base_property<T> {
public:
const T& get()const { return value; }
};
class ConstChild : public property<const int>{ };
I had the same need and I ended up with this quite manual approach :
class A
{
public:
void fooMutable(void) {}
void fooConst(void) const {}
};
class B : private A
{
public:
using A::fooConst;
const A& getParent(void) const
{
return *this;
}
};
void fooParent(const A&) {}
int main(void)
{
auto b = B{};
b.fooConst(); // Ok
b.fooMutable(); // Fail
fooParent(b); // Fail
fooParent(b.getParent()); // Ok
return 0;
}
Note that the using keyword would not work with overloads const/mutable :
class A
{
public:
void foo(void) {}
void foo(void) const {}
};
class B : private A
{
public:
using A::foo; // Expose the const and the mutable version
};
To solve this you could redefine the function yourself and call the parent :
class B : private A
{
public:
void foo(void) const
{
A::foo();
}
};
It can become pretty time consuming if you're inheriting a large hierarchy, but if it's for a not-so-big class it should be very reasonable and being quite natural for the user.
I have a trick, not a clean solution.
class ConstChild : private Property
{
operator const Property () { return *this; }
};
then
ConstChild cc;
cc.set(10); // ERROR
cc().get();