I'm trying to create an overloaded function that will be called with the dynamic type of an object. I try to do this without interfering with the actual class structure underneath, as I don't have direct access (i.e. I cannot add virtual methods, etc.)
As a concrete example, let's think of an AST class structure that looks somewhat like this:
class ASTNode {}; // this one is fully abstract; i.e. there's a virtual void method() = 0;
class Assignment : ASTNode {};
class Expression : ASTNode {};
class StringExpr : Expression {};
class MathExpr : Expression {};
I want to write a function act that will take an instance of ASTNode as parameter and, depending on its actual dynamic type do something different.
The call will be something like this
std::shared_ptr<ASTNode> parsedAST = get_a_parsed_ASTNode(); // ... received from some parser or library
act(parsedAST);
Then, I want to act, depending on the dynamic type of the ASTNode.
void act(std::shared_ptr<MathExpr> expr)
{
// Do something with Math expressions, e.g. evaluate their value
};
void act(std::shared_ptr<StringExpr> expr)
{
// Do something with String expressions, e.g. write their value to the log
};
void act(std::shared_ptr<Expression> expr)
{
// do something with other types of expressions (e.g. Boolean expressions)
};
Currently though, I cannot call since they dynamic type will be maybe not the ``most concrete type''. Instead, I have to manually create a dispatcher manually as follows, but the method is a bit silly in my opinion, since it does literally nothing else but dispatch.
void act(std::shared_ptr<ASTNode> node_ptr)
{
if(std::shared_ptr<MathExpr> derived_ptr = std::dynamic_pointer_cast<MathExpr>(node_ptr))
{
act(derived_ptr);
}
else if(std::shared_ptr<StringExpr> derived_ptr = std::dynamic_pointer_cast<StringExpr>(node_ptr))
{
act(derived_ptr);
}
else if(std::shared_ptr<Expression> derived_ptr = std::dynamic_pointer_cast<Expression>(node_ptr))
{
// do something with generic expressions. Make sure that this is AFTER the more concrete if casts
}
else if( ... ) // more of this
{
}
// more else if
else
{
// default action or raise invalid argument exception or so...
}
};
This is especially annoying & error-prone since my class hierarchy has many (> 20) different concrete classes that can be instantiated. Also, I have various act-functions, and when I refactor things (e.g. add an act for an additional type), I have to make sure to pay attention to the correct order of if(dynamic_pointer_cast) within the dispatcher.
Also it's not that stable, since a change in the underlying class hierarchy will require me to change every dispatcher directly, rather than just the specific act functions.
Is there a better / smarter solution? Evidently I'd appreciate "native" solutions, but I'm willing to consider libraries too.
Never encountered such problem myself, but can think of the following solution.
Create you hierarchy that mimics original hierarchy, has virtual act, the base has base pointer, and each cast it to the corresponding derived pointer.
Now, to create the needed wrapper, you don't need properly ordered dynamic_cast, dispach on typeid string. So your dispatch is a map from string to wrapper factory.
Sure you need RTTI for typeid string, but you would need it for dynamic_cast as well.
Related
I'm trying to convert the following C# code in to D, however I can't figure out how to make the template constraints work.
C# Implementation
public interface IComponent
{
}
public class Container
{
public T CreateComponent<T>() where T: IComponent, new()
{
// Trivial initialisation for example
var t = new T();
return t;
}
}
D Implementaiton
public interface Component
{
}
public class Container
{
public T createComponent(T)()
{
// Trivial initialisation for example
auto t = new T();
return t;
}
}
How can I re-create the "where T: IComponent" constraint?
I've tried various expressions combining is, typeof etc. but can't find anything that works.
Well, if all you're trying to do is require that T implement the interface IComponent, then is(T : IComponent) will test that T is implicitly convertible to IComponent (which is the case when IComponent is a base class of T or an interface that it implements). So, you'd end up with something like
public class Container
{
public T createComponent(T)()
if(is(T : IComponent))
{
// Trivial initialisation for example
auto t = new T();
return t;
}
}
Now, technically, other stuff can match if alias this is used to define an implicit conversion, which isn't likely to be common, but if you're being more paranoid about it, you could make the constraint also check that T is class - is(T == class).
public class Container
{
public T createComponent(T)()
if(is(T == class) && is(T : IComponent))
{
// Trivial initialisation for example
auto t = new T();
return t;
}
}
Then, T must be a class, and it must implicitly convert to IComponent. However, it is still technically possible for T to be a class which doesn't implement IComponent but does define an alias this which converts to an IComponent (it's just no longer possible for T to be a struct which does that). So, it's not perfect, but I don't know of a way to ensure that an implicit conversion is done via inheritance rather than alias this. So, unfortunately, I don't know of a way to absolutely guarantee that T is a class which implements IComponent. The most that I know how to do is to ensure that it implicitly converts to an `IComponent, which almost always means that it implements it.
However, the reality of the matter is that in the vast majority of cases, simply checking is(T : IComponent) is plenty, and depending on how your code is written, it might even work with a type which implicitly converts to IComponent but isn't actually an IComponent. So, the fact that alias this throws a spanner in the works may not actually be a problem. However, in general, alias this is a bane of generic code and why most generic code shouldn't be checking for implicit conversions. It's far too easy for a type to implicitly convert via alias this but not actually be converted in the function, in which case, it either won't compile, or it could have strange behavior if it supports the same operations that the target type does but those operations don't have the same results as they would if the original type were actually converted to the target type. So, if you actually want implicit conversions in templated code, you should force the implicit conversion by assigning the argument to the target type. But since you're looking to test for an interface rather than implicit conversions in general, what you probably want is a test which tests for that without allowing implicit conversions via alias this. Unfortunately, the only way that I know of to check at compile time whether one type derives from another or implements a specific interface is to check whether it implicitly converts to that base class or interface.
But maybe there's some fun voodoo with traits that's actually able to do it. If there is, we should probably add something to std.traits which does that for you, and if there isn't, maybe we should find a way to add it, since alias this can definitely be annoying if you don't want it. But fortunately, it's not a problem that comes up in most code, and if you're not writing a public API, then you only have to worry about it if you're declaring types with alias this. If you're not, then it really doesn't matter.
You don't even need a template constraint, just a template specialization:
T createComponent(T : IComponent)() { /* some code */ }
In typical fashion I found the answer moments after asking here http://ddili.org/ders/d.en/is_expr.html
public T addComponent(T)()
if (is(T: Component))
I'm trying to write a lightweight library for parsing C source code.
Here's the way I've considered writing a declaration parser:
Decl CParser::ParseDecl(std::istream& in);
Or something like:
void CParser::Parse(std::istream& in);
// and
virtual void CParser::OnDecl(const Decl& decl);
Where Decl is a base class that may be inherited by either a TypedefDecl, FunctionDecl, or VariableDecl.
Is it okay that client code will have to cast into a derived class to get more information about the declaration? Or is there a better way to do this?
Edit:
The function itself isn't very well defined yet, it may actually be a callback, like CParser::OnDecl(const Decl& decl); which may be overloaded by a derived class like CFomatter: public CParser or something. That's not entirely part of the question.
I'm really just curious if it's okay that a client of the library will have to cast the Decl object. There's a lot of different declaration types in the C language (even more in C++) and it seems like writing a callback or a parser for each one of them would be just as bad as having to derive the base class.
First, of all you have to avoid slicing, for example by returning a a pointer.
Decl* CParser::ParseDecl(std::istream& in);
Then, generally speaking, forcing a client to cast a return value is a symptom of a bad design. What if he casts to the wrong type ? How shall he know to which type he has to cast ? If the user makes the wrong cast, it's undefined behaviour (and extremely nasty bugs).
CParser cp;
...
Decl* token = cp.ParseDecl(ifs);
FunctionDecl *ftoken;
VariableDecl *vtoken;
if (????) { // <============ how does your user know ?
ftoken = static_cast<FunctionDecl>(token);
//... do something with ftoken specific to function declarations
}
else if (????) {
vtoken = static_cast<VariableDecl>(token);
//... do something specific for variable declarations
}
To make the things more robust, you should at least make the type polymorphic, by having one or more virtual functions. Then your client can use the safer dynamic casting and make the right decision (which returns nullptr in case of wrong casting):
...
if (ftoken = dynamic_cast<FunctionDecl>(token)) { // If wrong type fotken will be set to nullptr and you go to the else part
//... do something with ftoken specific to function declarations
}
else if (vtoken = dynamic_cast<VariableDecl>(token)) { // attention: it's = and not ==
//... do something specific for variable declarations
}
This would be an acceptable design. But if you have polymorphic types, you could rethink your design by making use of this polymorphism, instead of forcing user to take care of casting. One possible way could for example be to define class specific functions as polymorphic ones:
class Decl {
public:
virtual void display_details() { cout << "No detail for this token"; }
...
};
class VariableDecl : public Decl {
...
display_details() { cout<<"This is variable "<<name; }
};
class FunctionDecl : public Decl {
...
display_details() { cout<<"This is function "<<name<<" with "<<nparam<< " parameters"; }
};
The user could then just refer to the specific building blocs, without worying to much about the real type of the object:
Decl* token = cp.ParseDecl(ifs);
token->display_details();
Another popular design for more complex situations is the visitor design pattern. This is for example used by boost::variant : it could be worth looking at their examples, event if you don't intend to use this library.
In C# I can define this:
public interface BaseObject
{
int GetValue();
}
public class Test<T> where T : BaseClass
{
T BaseObject;
}
which means I know that I can alwaysa call BaseObject.GetValue() / BaseObject->GetValue(); because I know that the baseobject has this method.
Is there a similiar way to do this in C++? So that I can define an interface that multiple classes can inherit and a class that can take advantage of this.
Templates, which are even more powerful than C# generics (not to say they are necessarily better, just different).
template<class T>
class foo
{
public:
int whatever()
{
return obj.GetValue();
}
private:
T obj;
};
A separate class is created for each template argument you use. If you provide a template type which would result in an error you will know at compile time.
You're asking about C++ concepts, a way to specify requirements for template parameters. They were proposed during the work on C++11, but proved complicated enough that they weren't done in time. But they've just been delayed, not forgotten.
In the meantime, duck typing remains very powerful, and it will catch when you pass a template parameter that doesn't have the required interface. It just won't report the problem as neatly.
As a workaround, a simple way to check the constraint you showed takes advantage of the fact that pointer conversions are implicit only when upcasting:
public class Test<T> where T : BaseClass
{
static T* enforcement_helper = 0;
static BaseClass* enforce_inheritance_constraint = enforcement_helper;
};
Depending on how new your compiler is, you may need to put those lines inside a special member function (destructor is good, because it's almost always processed).
But you should only check constraints in order to improve error messages (by causing the failure in a clearly commented section of code). C++ templates are duck typed, and they will work with any template parameters that provide the required operations. No formal "interface" is required.
i have a class with the following structure:
class myClass
{
private:
int type;
classOne objectOne;
classTwo objectTwo;
public:
myClass(classOne object)
{
this->objectOne = object;
this->type = 0;
}
myClass(classTwo object)
{
this->objectTwo = object;
this->type = 1;
}
}
i now want a method returning an object of type classOne if type is 0 and of type classTwo if type is 1. I do not want two methods to achieve this. the classes have different structures.
Is this even possible? Any suggestions are appreciated :)
You can use Boost.Variant to do this. A variant can be constructed directly from any value convertible to one of its bounded types. Similarly, a variant can be assigned any value convertible to one of its bounded types. Heres how you could use it in your class:
class myClass
{
private:
boost::variant<classOne, classTwo> obj;
public:
myClass(classOne object) : obj(object)
{
}
myClass(classTwo object) : obj(object)
{
}
};
It also provides a very convenient boost::get to retrieve the value from the variant.
You can use that to supply code for each bounded type you have(ie classOne and classTwo). Here is an example:
if (classOne * x = boost::get<classOne>(&obj))
{
//Code for classOne
}
else if (classTwo * x = boost::get<classTwo>(&obj)
{
//Code for classTwo
}
However, such code is quite brittle, and without careful attention will likely lead to the introduction of subtle logical errors detectable only at runtime. Thus, real-world use of variant typically demands an access mechanism more robust than get. For this reason, variant supports compile-time checked visitation via apply_visitor. Visitation requires that the programmer explicitly handle (or ignore) each bounded type. Failure to do so results in a compile-time error.
Visitation of a variant requires a visitor object. Like this:
class object_visitor
: public boost::static_visitor<>
{
public:
void operator()(classOne & x) const
{
//Code for classOne
}
void operator()(classTwo & x) const
{
//Code for classTwo
}
};
With the implementation of the above visitor, we can then apply it to obj, as seen in the following:
boost::apply_visitor( object_visitor(), obj );
Unless the two types are related (in which case you can create a function that will return a pointer/reference to the common ancestor) you cannot do that directly in C++.
C++ is a statically typed language, meaning that the type of every expression must be known at compile time, but you are trying to define a function whose return type depends on runtime values.
Depending on the particular problem to solve, there might be different approaches that you could take, including using type erasure (return a boost::any, boost::variant or your own type-erasure).
ClassOne and ClassTwo need to have the same return type then either via inheritance or composition. i.e ClassOne and ClassTwo need to be subclasses of the same super class OR they need to impl the same interface.
I am not sure why you would not use templates for your case.
You can have something like below:
template <class ClassType>
class myClass
{
private:
int type;
ClassType object;
public:
myClass(ClassType object_in)
{
this->object = object_in;
/*
C++ doesn't support reflection so I don't think there
is a robust way of doing the following at runtime.
*/
type = /* Get Type at runtime */;
}
/*
Have another method which return object in a straigtforward way.
*/
};
However, then this become trivial. Any more insight into what your use case is, such that you have to know the type?
Update:
If the ClassType is going to be an Object, you can have a const static int TypeID member for the class, which is set at compile time. You can then use it determine the Type at runtime.
If they're completely different structures, with no common base then an alternative way you can return them from the same function is to use void*.
However that's bad form in C++, usually indicating a design failure - either use two different functions, or use a common base class.
It's apples and oranges. If you put an apple into an recipe that calls for an orange it won't be the same recipe anymore.
The use of type-id is a sign that you need virtual functions for myClass. Even if the other two classes are totally independent, the fact that they are returned by the same function could easily make them inherit a base class. And also you can just return a pair containing class1, class2 and one of them can be null.
The first problem is how you will determine the class of which type has been returned. I think it is possible to return a pointer to structure of this type
struct res {
myClass* c1;
ClassOne* c2;
} ;
The field of the not chosen class is NULL, the other points to the object.
I have an interesting problem. Consider this class hierachy:
class Base
{
public:
virtual float GetMember( void ) const =0;
virtual void SetMember( float p ) =0;
};
class ConcreteFoo : public Base
{
public:
ConcreteFoo( "foo specific stuff here" );
virtual float GetMember( void ) const;
virtual void SetMember( float p );
// the problem
void foo_specific_method( "arbitrary parameters" );
};
Base* DynamicFactory::NewBase( std::string drawable_name );
// it would be used like this
Base* foo = dynamic_factory.NewBase("foo");
I've left out the DynamicFactory definition and how Builders are
registered with it. The Builder objects are associated with a name
and will allocate a concrete implementation of Base. The actual
implementation is a bit more complex with shared_ptr to handle memory
reclaimation, but they are not important to my problem.
ConcreteFoo has class specific method. But since the concrete instances
are create in the dynamic factory the concrete classes are not known or
accessible, they may only be declared in a source file. How can I
expose foo_specific_method to users of Base*?
I'm adding the solutions I've come up with as answers. I've named
them so you can easily reference them in your answers.
I'm not just looking for opinions on my original solutions, new ones
would be appreciated.
The cast would be faster than most other solutions, however:
in Base Class add:
void passthru( const string &concreteClassName, const string &functionname, vector<string*> args )
{
if( concreteClassName == className )
runPassThru( functionname, args );
}
private:
string className;
map<string, int> funcmap;
virtual void runPassThru( const string &functionname, vector<string*> args ) {}
in each derived class:
void runPassThru( const string &functionname, vector<string*> args )
{
switch( funcmap.get( functionname ))
{
case 1:
//verify args
// call function
break;
// etc..
}
}
// call in constructor
void registerFunctions()
{
funcmap.put( "functionName", id );
//etc.
}
The CrazyMetaType solution.
This solution is not well thought out. I was hoping someone might
have had experience with something similar. I saw this applied to the
problem of an unknown number of a known type. It was pretty slick. I
was thinking to apply it to an unkown number of unknown type***S***
The basic idea is the CrazyMetaType collects the parameters is type
safe way, then executing the concrete specific method.
class Base
{
...
virtual CrazyMetaType concrete_specific( int kind ) =0;
};
// used like this
foo->concrete_specific(foo_method_id) << "foo specific" << foo_specific;
My one worry with this solution is that CrazyMetaType is going to be
insanely complex to get this to work. I'm up to the task, but I
cannot count on future users to be up to be c++ experts just to add
one concrete specific method.
Add special functions to Base.
The simplest and most unacceptable solution is to add
foo_specific_method to Base. Then classes that don't
use it can just define it to be empty. This doesn't work because
users are allowed to registers their own Builders with the
dynamic_factory. The new classes may also have concrete class
specific methods.
In the spirit of this solution, is one slightly better. Add generic
functions to Base.
class Base
{
...
/// \return true if 'kind' supported
virtual bool concrete_specific( int kind, "foo specific parameters" );
};
The problem here is there maybe quite a few overloads of
concrete_specific for different parameter sets.
Just cast it.
When a foo specific method is needed, generally you know that the
Base* is actually a ConcreteFoo. So just ensure the definition of class
ConcreteFoo is accessible and:
ConcreteFoo* foo2 = dynamic_cast<ConcreteFoo*>(foo);
One of the reasons I don't like this solution is dynamic_casts are slow and
require RTTI.
The next step from this is to avoid dynamic_cast.
ConcreteFoo* foo_cast( Base* d )
{
if( d->id() == the_foo_id )
{
return static_cast<ConcreteFoo*>(d);
}
throw std::runtime_error("you're screwed");
}
This requires one more method in the Base class which is completely
acceptable, but it requires the id's be managed. That gets difficult
when users can register their own Builders with the dynamic factory.
I'm not too fond of any of the casting solutions as it requires the
user classes to be defined where the specialized methods are used.
But maybe I'm just being a scope nazi.
The cstdarg solution.
Bjarn Stroustrup said:
A well defined program needs at most few functions for which the
argument types are not completely specified. Overloaded functions and
functions using default arguments can be used to take care of type
checking in most cases when one would otherwise consider leaving
argument types unspecified. Only when both the number of arguments and
the type of arguments vary is the ellipsis necessary
class Base
{
...
/// \return true if 'kind' supported
virtual bool concrete_specific( int kind, ... ) =0;
};
The disadvantages here are:
almost no one knows how to use cstdarg correctly
it doesn't feel very c++-y
it's not typesafe.
Could you create other non-concrete subclasses of Base and then use multiple factory methods in DynamicFactory?
Your goal seems to be to subvert the point of subclassing. I'm really curious to know what you're doing that requires this approach.
If the concrete object has a class-specific method then it implies that you'd only be calling that method specifically when you're dealing with an instance of that class and not when you're dealing with the generic base class. Is this coming about b/c you're running a switch statement which is checking for object type?
I'd approach this from a different angle, using the "unacceptable" first solution but with no parameters, with the concrete objects having member variables that would store its state. Though i guess this would force you have a member associative array as part of the base class to avoid casting to set the state in the first place.
You might also want to try out the Decorator pattern.
You could do something akin to the CrazyMetaType or the cstdarg argument but simple and C++-ish. (Maybe this could be SaneMetaType.) Just define a base class for arguments to concrete_specific, and make people derive specific argument types from that. Something like
class ConcreteSpecificArgumentBase;
class Base
{
...
virtual void concrete_specific( ConcreteSpecificArgumentBase &argument ) =0;
};
Of course, you're going to need RTTI to sort things out inside each version of concrete_specific. But if ConcreteSpecificArgumentBase is well-designed, at least it will make calling concrete_specific fairly straightforward.
The weird part is that the users of your DynamicFactory receive a Base type, but needs to do specific stuff when it is a ConcreteFoo.
Maybe a factory should not be used.
Try to look at other dependency injection mechanisms like creating the ConcreteFoo yourself, pass a ConcreteFoo type pointer to those who need it, and a Base type pointer to the others.
The context seems to assume that the user will be working with your ConcreteType and know it is doing so.
In that case, it seems that you could have another method in your factory that returns ConcreteType*, if clients know they're dealing with concrete type and need to work at that level of abstraction.