I was reading about encapsulated polymorphism and I came across a piece of code like that:
template <typename T>
struct Model<T> : Concept
{
Model<T>(T impl) :
mImpl(std::forward<T>(impl))
{
}
virtual Concept* clone() const override
{
return new Model<T>(mImpl)
}
virtual void operator (const LogMessage::Meta& meta, const std::string& message) override
{
mImpl(meta, message);
}
T mImpl;
};
What is the point of forwarding impl in Model constructor?
Does it make sense to forward an argument if it is passed by value?
If Model<T> where T is an lvalue reference type (e.g. X&) is legal (according to Model's documentation), then forward is the correct tool to use here. Otherwise (if T should always be an object type), move is the correct tool.
That being said, the clone member function makes it look like T should only be an object type. And so move would be a better tool to use here. And in this case forward isn't technically wrong, but simply confusing as it raises exactly the question the OP asks.
Related
I might simply be overlooking something or being stupid, in which case I am sorry, but I'm really not sure how to, if it is even possible, access a virtual member function. Actually, the virtual part is a second issue about a possible solution I will describe later. Here's some example code that summarizes my issue:
class BaseClass
{
public:
virtual std::string ClassName()
{
return "BaseClass";
}
};
class DerivedClass : public BaseClass
{
public:
std::string ClassName()
{
return "DerivedClass";
}
};
template<class cT>
void StatusPrint(const std::string& message)
{
return cT.ClassName(); // Here's where my issue arises.
}
So, I tried to replace cT. with ct::, however, while that causes compiler issues on its own, it also tries to access the virtual function in BaseClass, but I want to access the overridden function in DerivedClass.
Is what I am trying to do possible like this?
Sorry if I'd seem rude, but you cannot return anything from void function. So apparently, we don't have the full story here.
Do you really want a compile time solution?
Looking at your code, it seems that className() does not use at all the state of the object. So you could make it static (instead of virtual). THe problem would then be solved with:
template<class cT>
std::string StatusPrint(const std::string& message) // returns string, not void
{
return cT::ClassName(); // :: if class name is static.
}
Since the template cannot derive the type from its argument, you'd need to provide it, making the choice of the class completely compile-time:
cout<< StatusPrint<DerivedClass>("test"s)<<endl;
This kind of practice is used, when you have some utility classes and you want to configure at compile time which one to use.
Do you want a dynamic solution?
If you want a dynamic solution at runtime, you need to use some object, because virtual require an object that knows its dynamic type at runtime.
Then it depends on the context. One solution is to use a cT parameter, with the advantage of parameter deduction:
template<class cT>
std::string StatusPrint ( cT object, const std::string& message)
{
return object.ClassName(); // Here's where my issue arises.
}
You'd then call it:
DerivedClass test;
...
cout<< StatusPrint(test, "test"s)<<endl;
Online Demo
But of course, it could also use some global object instead (but the template makes then much less sense), or better, an object in a template class if you refactor StatusPrint() to be a member function of such a class.
I'm not sure what exactly you are trying to do, but see if this is more like it:
std::string StatusPrint(BaseClass *instance) {
return instance->ClassName();
}
Template parameters are for types, virtual inheritance needs pointers.
DerivedClass derived;
std::cout << StatusPrint(&derived) << std::endl; // note the &
cT is a type, not an object. You can only call functions on object instances (unless they're static functions, but that's not what you're trying to do here). You need to pass in an instance of the object you want to print out. e.g.
template<class T>
std::string StatusPrint(const T& obj, const std::string& message)
{
return obj.ClassName();
}
It's also customary to name template types with Uppercase to avoid this confusion.
I have to admit the compiler error for this is confusing, but it does give you a hint that there's something wrong with cT. It's saying that what comes before . is not what it was expecting.
With GCC 9:
error: expected primary-expression before '.' token
24 | return cT.ClassName();
| ^
Consider the following abstract class, which will be the interface for a class that writes the information carried by some object to standard output.
class FileBuilder
{
public:
virtual void build(const Object& object) = 0;
virtual ~FileBuilder() = default;
};
At this point I will note that Object is also an abstract class with derived class SpecialObject. Now I am going to implement SpecialFileBuilder : FileBuilder, as follows.
class SpecialFileBuilder : public FileBuilder
{
public:
void build(const SpecialObject& specialObject);
};
...
void SpecialFileBuilder::build(const SpecialObject& specialObject)
{
// Do some stuff
}
I don't fully understand why this should not be possible. SpecialFileBuilder respects the interface FileBuilder, and everywhere which expects a FileBuilder can instead be given a SpecialFileBuilder. I appreciate your help in advance.
Of course, this would work if I changed things to the following.
void SpecialFileBuilder::build(const Object& object)
However, in my implementation of SpecialFileBuilder::build() I need to use the fact that the argument is a SpecialObject, not just an Object.
How should I instead approach this design?
TL;DR no, this does not make any sense.
Full version below.
I don't fully understand why this should not be possible.
virtual void build(const Object& object) = 0;
This declaration is a promise. It promises that build can accept any Object as an argument. Such promises are legally binding for derived classes, i.e. they must implement the promise as stated by the base class. Note the declaration does not promise that build can accept some objects and not others.
FileBuilder* builder = GetBuilder(); // we don't know what kind of builder it is
SpecialObject some;
builder->build(some); // must work
OtherSpecialObject some;
builder->build(other); // must work too
UnrelatedObject whatever;
builder->build(whatever); // must work as well
Now looking at the other declaration
void build(const SpecialObject& specialObject);
It reneges on the promise. The original promise is strong. Give me any object, I can deal with it. The new promise is weak. Oh, I am a special little builder, I can only cope with special little objects!
Sorry bud, you cannot override a strong promise with a weaker one. If you were allowed to, how would we be able to trust any promise?
Now if your design doesn't fit in this outline, i.e. you always know what kind of builder you get, and you don't want to promise to cope with all kinds of objects, then you have selected a wrong tool for the job. Perhaps you want to give generic programming a try.
template <typename T>
class FileBuilder {
virtual void build (const T& t) = 0;
};
class SpecialBuilder: public FileBuilder<SpecialObject> {
void build (const SpecialObject& t) override;
};
Now the code above won't work, we need to fix it
FileBuilder<SpecialObject>* builder = GetBuilder<SpecialObject>(); // we know exactly what we want to build
SpecialObject some;
builder->build(some); // will work;
OtherSpecialObject other;
builder->build(other); // sorry that's not in the contract, won't compile
I don't fully understand why this should not be possible. SpecialFileBuilder respects the interface FileBuilder, and everywhere which expects a FileBuilder can instead be given a SpecialFileBuilder
You may have covariant return type.
But for argument, you would need contra-variant return type (which is not supported in C++).
As following code should be correct
SpecialFileBuilder specialFileBuilder;
FileBuilder& fileBuilder;
SpecialObject2 specialObject2; // Other derived class, unrelated to SpecialObject
Object& object = specialObject2;
fileBuilder.build(object); // correct type
// but
specialFileBuilder.build(specialObject2); // won't compile
contra-variant parameter would be
struct Base {
virtual void f(const Cat&) = 0;
};
struct Derived : Base
{
void f(const Animal&) override; // if contra-variance was supported
};
So, I have something along the lines of these structs:
struct Generic {}
struct Specific : Generic {}
At some point I have the the need to downcast, ie:
Specific s = (Specific) GetGenericData();
This is a problem because I get error messages stating that no user-defined cast was available.
I can change the code to be:
Specific s = (*(Specific *)&GetGenericData())
or using reinterpret_cast, it would be:
Specific s = *reinterpret_cast<Specific *>(&GetGenericData());
But, is there a way to make this cleaner? Perhaps using a macro or template?
I looked at this post C++ covariant templates, and I think it has some similarities, but not sure how to rewrite it for my case. I really don't want to define things as SmartPtr. I would rather keep things as the objects they are.
It looks like GetGenericData() from your usage returns a Generic by-value, in which case a cast to Specific will be unsafe due to object slicing.
To do what you want to do, you should make it return a pointer or reference:
Generic* GetGenericData();
Generic& GetGenericDataRef();
And then you can perform a cast:
// safe, returns nullptr if it's not actually a Specific*
auto safe = dynamic_cast<Specific*>(GetGenericData());
// for references, this will throw std::bad_cast
// if you try the wrong type
auto& safe_ref = dynamic_cast<Specific&>(GetGenericDataRef());
// unsafe, undefined behavior if it's the wrong type,
// but faster if it is
auto unsafe = static_cast<Specific*>(GetGenericData());
I assume here that your data is simple.
struct Generic {
int x=0;
int y=0;
};
struct Specific:Generic{
int z=0;
explicit Specific(Generic const&o):Generic(o){}
// boilerplate, some may not be needed, but good habit:
Specific()=default;
Specific(Specific const&)=default;
Specific(Specific &&)=default;
Specific& operator=(Specific const&)=default;
Specific& operator=(Specific &&)=default;
};
and bob is your uncle. It is somewhat important that int z hae a default initializer, so we don't have to repeat it in the from-parent ctor.
I made thr ctor explicit so it will be called only explicitly, instead of by accident.
This is a suitable solution for simple data.
So the first step is to realize you have a dynamic state problem. The nature of the state you store changes based off dynamic information.
struct GenericState { virtual ~GenericState() {} }; // data in here
struct Generic;
template<class D>
struct GenericBase {
D& self() { return *static_cast<D&>(*this); }
D const& self() const { return *static_cast<D&>(*this); }
// code to interact with GenericState here via self().pImpl
// if you have `virtual` behavior, have a non-virtual method forward to
// a `virtual` method in GenericState.
};
struct Generic:GenericBase<Generic> {
// ctors go here, creates a GenericState in the pImpl below, or whatever
~GenericState() {} // not virtual
private:
friend struct GenericBase<Generic>;
std::unique_ptr<GenericState> pImpl;
};
struct SpecificState : GenericState {
// specific stuff in here, including possible virtual method overrides
};
struct Specific : GenericBase<Specific> {
// different ctors, creates a SpecificState in a pImpl
// upcast operators:
operator Generic() && { /* move pImpl into return value */ }
operator Generic() const& { /* copy pImpl into return value */ }
private:
friend struct GenericBase<Specific>;
std::unique_ptr<SpecificState> pImpl;
};
If you want the ability to copy, implement a virtual GenericState* clone() const method in GenericState, and in SpecificState override it covariantly.
What I have done here is regularized the type (or semiregularized if we don't support move). The Specific and Generic types are unrelated, but their back end implementation details (GenericState and SpecificState) are related.
Interface duplication is avoided mostly via CRTP and GenericBase.
Downcasting now can either involve a dynamic check or not. You go through the pImpl and cast it over. If done in an rvalue context, it moves -- if in an lvalue context, it copies.
You could use shared pointers instead of unique pointers if you prefer. That would permit non-copy non-move based casting.
Ok, after some additional study, I am wondering if what is wrong with doing this:
struct Generic {}
struct Specific : Generic {
Specific( const Generic &obj ) : Generic(obj) {}
}
Correct me if I am wrong, but this works using the implicit copy constructors.
Assuming that is the case, I can avoid having to write one and does perform the casting automatically, and I can now write:
Specific s = GetGenericData();
Granted, for large objects, this is probably not a good idea, but for smaller ones, will this be a "correct" solution?
I have a class messenger which relies on a printer instance. printer is a polymorphic base class and the actual object is passed to the messenger in the constructor.
For a non-polymorphic object, I would just do the following:
class messenger {
public:
messenger(printer const& pp) : pp(pp) { }
void signal(std::string const& msg) {
pp.write(msg);
}
private:
printer pp;
};
But when printer is a polymorphic base class, this no longer works (slicing).
What is the best way to make this work, considering that
I don’t want to pass a pointer to the constructor, and
The printer class shouldn’t need a virtual clone method (= needs to rely on copy construction).
I don’t want to pass a pointer to the constructor because the rest of the API is working with real objects, not pointers and it would be confusing / inconsistent to have a pointer as an argument here.
Under C++0x, I could perhaps use a unique_ptr, together with a template constructor:
struct printer {
virtual void write(std::string const&) const = 0;
virtual ~printer() { } // Not actually necessary …
};
struct console_printer : public printer {
void write(std::string const& msg) const {
std::cout << msg << std::endl;
}
};
class messenger {
public:
template <typename TPrinter>
messenger(TPrinter const& pp) : pp(new TPrinter(pp)) { }
void signal(std::string const& msg) {
pp->write(msg);
}
private:
std::unique_ptr<printer> pp;
};
int main() {
messenger m((console_printer())); // Extra parens to prevent MVP.
m.signal("Hello");
}
Is this the best alternative? If so, what would be the best way in pre-0x? And is there any way to get rid of the completely unnecessary copy in the constructor? Unfortunately, moving the temporary doesn’t work here (right?).
There is no way to clone polymorphic object without a virtual clone method. So you can either:
pass and hold a reference and ensure the printer is not destroyed before the messenger in the code constructing messenger,
pass and hold a smart pointer and create the printer instance with new,
pass a reference and create printer instance on the heap using clone method or
pass a reference to actual type to a template and create instance with new while you still know the type.
The last is what you suggest with C++0x std::unique_ptr, but in this case C++03 std::auto_ptr would do you exactly the same service (i.e. you don't need to move it and they are otherwise the same).
Edit: Ok, um, one more way:
Make the printer itself a smart pointer to the actual implementation. Than it's copyable and polymorphic at the same time at the cost of some complexity.
Expanding the comment into a proper answer...
The primary concern here is ownership. From you code, it is appears that each instance of messenger owns its own instance of printer - but infact you are passing in a pre-constructed printer (presumably with some additional state), which you need to then copy into your own instance of printer. Given the implied nature of the object printer (i.e. to print something), I would argue that the thing to which is it is printing is a shared resource - in that light, it makes no sense for each messenger instance to have it's own copy of printer (for example, what if you need to lock to access to std::cout)?
From a design point of view, what messenger needs on construction is actually really a pointer to some shared resource - in that light, a shared_ptr (better yet, a weak_ptr) is a better option.
Now if you don't want to use a weak_ptr, and you would rather store a reference, think about whether you can couple messenger to the type of printer, the coupling is left to the user, you don't care - of course the major drawback of this is that messenger will not be containable. NOTE: you can specify a traits (or policy) class which the messenger can be typed on and this provides the type information for printer (and can be controlled by the user).
A third alternative is if you have complete control over the set of printers, in which case hold a variant type - it's much cleaner IMHO and avoids polymorphism.
Finally, if you cannot couple, you cannot control the printers, and you want your own instance of printer (of the same type), the conversion constructor template is the way forward, however add a disable_if to prevent it being called incorrectly (i.e. as normal copy ctor).
All-in-all, I would treat the printer as a shared resource and hold a weak_ptr as frankly it allows better control of that shared resource.
Unfortunately, moving the temporary doesn’t work here (right?).
Wrong. To be, uh, blunt. This is what rvalue references are made for. A simple overload would quickly solve the problem at hand.
class messenger {
public:
template <typename TPrinter>
messenger(TPrinter const& pp) : pp(new TPrinter(pp)) { }
template <typename TPrinter>
messenger(TPrinter&& pp) : pp(new TPrinter(std::move(pp))) { }
void signal(std::string const& msg) {
pp->write(msg);
}
private:
std::unique_ptr<printer> pp;
};
The same concept will apply in C++03, but swap unique_ptr for auto_ptr and ditch the rvalue reference overload.
In addition, you could consider some sort of "dummy" constructor for C++03 if you're OK with a little dodgy interface.
class messenger {
public:
template <typename TPrinter>
messenger(TPrinter const& pp) : pp(new TPrinter(pp)) { }
template<typename TPrinter> messenger(const TPrinter& ref, int dummy)
: pp(new TPrinter())
{
}
void signal(std::string const& msg) {
pp->write(msg);
}
private:
std::unique_ptr<printer> pp;
};
Or you could consider the same strategy that auto_ptr uses for "moving" in C++03. To be used with caution, for sure, but perfectly legal and doable. The trouble with that is that you're influencing all printer subclasses.
Why don't you want to pass a pointer or a smart pointer?
Anyway, if you're always initializing the printer member in the constructor you can just use a reference member.
private:
printer& pp;
};
And initialize in the constructor initialization list.
When you have a golden hammer everything looks like nails
Well, my latest golden hammer is type erasure. Seriously I would not use it, but then again, I would pass a pointer and have the caller create and inject the dependency.
struct printer_iface {
virtual void print( text const & ) = 0;
};
class printer_erasure {
std::shared_ptr<printer_iface> printer;
public:
template <typename PrinterT>
printer_erasure( PrinterT p ) : printer( new PrinterT(p) ) {}
void print( text const & t ) {
printer->print( t );
}
};
class messenger {
printer_erasure printer;
public:
messenger( printer_erasure p ) : printer(p) {}
...
};
Ok, arguably this and the solutions provided with a template are the exact same thing, with the only slight difference that the complexity of type erasure is moved outside of the class. The messenger class has its own responsibilities, and the type erasure is not one of them, it can be delegated.
How about templatizing the class messanger ?
template <typename TPrinter>
class messenger {
public:
messenger(TPrinter const& obj) : pp(obj) { }
static void signal(printer &pp, std::string const& msg) //<-- static
{
pp->write(msg);
}
private:
TPrinter pp; // data type should be template
};
Note that, signal() is made static. This is to leverage the virtual ability of class printer and to avoid generating a new copy of signal(). The only effort you have to make is, call the function like,
signal(this->pp, "abc");
Suppose you have other datatypes then pp which are not related to template type, then those can be moved to a non template base class and that base can be inherited by messenger. I am not describing in much details but, I wish the point should be clearer.
Trying to find a "simple to use" safe_bool idiom/implementation, I've ended up with my own.
Q: Is this implementation correct?
template <typename T>
class safe_bool
{
protected:
typedef void (safe_bool::*bool_type)() const;
bool_type to_bool_type(bool b) const
{ return b ? &safe_bool<T>::safe_bool_true : 0; }
private:
void safe_bool_true() const {}
private:
bool operator ==(safe_bool<T> const & rhs);
bool operator !=(safe_bool<T> const & rhs);
};
to be used like this:
struct A : public safe_bool<A>
{
// operator bool() const { return true; }
operator bool_type() const { return to_bool_type(true); }
};
The only addition to existing base classes would be to_bool_type, but I hope I've got everything else correct, too.
The test cases I used (VC9) can be found here.
The downsides I see in implementation: bool_type and to_bool_type are visible in derived classes, which might not appease to everyone. Also, using the wrong template argument (e.g. class B : public safe_bool<A> introduced during copy-and-paste) will go unnoticed.
The “wrong template argument” problem you mentioned is almost completely eliminated by the static_cast in the wikibooks.org solution (“for testability without virtual functions”) cited by #Terry Mahaffey. The only thing I can see wrong with their solution is the separate safe_bool_base class, which will suppress the empty base optimization when it appears in multiple base classes (or elements in a compressed_pair). Personally, I'd move that implementation back up into the template.
Using a pointer to a member function as the bool alias is idiomatic, as you're doing here.
Your implementation looks correct for what is there, but slightly incomplete. See http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Safe_bool
IMO safe_bool falls into the category of things which do more harm than good; ie the complexity and confusion introduced by this idiom along with the mental effort needed to understand it are greater than the intial problem it is intending to solve.