alternative to virtual typedef - c++

I have an interface IEnumerable for template classes of List<>, Array<> and Dictionary<>. I was hoping to use typedef to get their templated types T.
I was hoping to do the following.
class IEnumerable
{
public:
virtual typedef int TemplateType;
}
And then override in inherited member, but you cant make a virtual typedef. So is there any other way that i could get the type of an unknown template class (IEnumerable is not template)?

Well, here is what is discussed in the comments in case somebody with the same question later finds this.
Basically, you want to do something similar to C#'s List<>, Array<>, IEnumerable and IEnumerator. However, you don't want to have to create a generic parent class Object because it may mean that you'll need to dynamic_cast every time.
Additionally, you don't want to make IEnumerable a template because you don't want to have to know the type when using the collection.
In fact, with C++11, you can make IEnumerable a template and not have to know the type by using the implicit type keyword auto, which is the C++11 equivalent of c#'s var keyword.
So to do this, what you can do is:
template <class T>
class IEnumerable {
public:
virtual IEnumerator<T> getEnumerator() = 0;
// and more stuff
}
then
template <class T>
class List : public IEnumerable<T> {
public:
virtual IEnumerator<T> getEnumerator() {
return ListEnumerator<T>(this);
}
}
and
template <class T>
class ListEnumerator : public IEnumerator<T> {
public:
T getNext(); // or something to this effect
// and more stuff
}
Finally, when it comes to using it, you can do:
List<int> myList;
auto i = myList.getEnumerator();
int z = i.getNext()+1;

Related

How can I implement the visitor patter with return type in C++

I want to implement the visitor pattern for one of my class without having to depend on the types that will implement the interface to visit them.
My solution was this:
class model::VisitableNode {
public:
template<class T>
virtual T accept(NodeVisitor<T>);
}
But C++ says that it doesn't support template + virtual methods
Node in my application will have only one implementation but if I don't use a template return type my model class will depend on the toolkit that I'm using to create the graphic for my app.
If a visitor needs to return a value, it is normal to store the returned value in the visitor itself. Thus:
NodeVisitor<double> dv;
node->accept(dv);
double result = dv.result();
If you don't like the boilerplate, you can wrap it in a non-virtual member:
class model::VisitableNode {
public:
template<class T>
/* non-virtual */ T accept(NodeVisitor<T>& v) {
do_accept(v);
return v.result;
}
virtual void do_accept(NodeVisitorBase& v) = 0;
}
Why not template the class itself?
template<class T>
class model::VisitableNode<T> {
public:
virtual T accept(NodeVisitor<T>);
}

Create a templated variable within a templated class of a different type

I'm not sure what I am asking for is possible.
I have a templated class called Controller. This is a variadic template class which takes multiple classes and can set their values as such.
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
This takes a bunch of different classes together and allows me to to set their values at the same time. setValues is a templated function which allows any type to be passed in. However, right now I am trying to modify my class so that I can set a value within the controller itself for easy retrieval. However this is the part that is proving difficult.
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
private:
std::tuple<Classes&...> objects;
};
I want to add the following as a private variable T controllerValue; However, I know that I cannot simply declare T because we cannot define member templates and the compiler has no idea what to expect. Which then I tried to create a private struct:
template<typename T>
struct ControllerValue { T value; };
However, I cannot define a struct underneath that, because the same problem occurs. The compiler has no idea what type ControllerValue is. What I would like is something like this:
template<typename...Classes>
class Controller
{
public:
Controller(Classes&...objects) : objects(objects...){}
Controller(std::tuple<Classes&...> tup) : objects(tup){}
template<typename T>
void setValues(T value)
{
thisValue.value = value;
std::apply([&](auto&...x) { x.updateValue(value),...);}, objects); //calls the updateValue function for each class
}
template<typename T>
T getValue() const { return thisValue.value }
private:
std::tuple<Classes&...> objects;
template<typename T>
struct ControllerValue { T value; };
ControllerValue thisValue;
};
This will not compile at all for the same reason that the compiler has no idea what type ControllerValue should be. And this is where I am stuck. Is this even possible to do? If not, what is another way that I can make this work?
To clear up confusion, the use case would be something like this:
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32);
int commonValue = myController->getValue();
or
Controller<ClassA,ClassB,ClassC>* myController = new Controller<ClassA,ClassB,ClassC>(*a,*b,*c);
myController->setValues(32.3);
double commonValue = myController->getValue();
I think solving this exact problem is impossible in C++ (and still very cumbersome in languages with runtime generics). You can very easily create a polymorphic class that can only store any value:
class PolymorphicBase
{
public:
virtual ~PolymorphicBase() = default;
};
template <class T>
class PolymorphicObject : public PolymorphicBase
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
};
A member of std::unique_ptr<PolymorphicBase> can sufficiently store any value, but how would such a value be retrieved? Probably the easiest is to expose the reference to PolymorphicBase and use dynamic type checks to see if the type is compatible with something you know, but what if you need the code to work for any type?
This is what lambdas with auto parameters are useful for. However, you would have to be able to pass such a lambda to a method on PolymorphicBase and implement that method in PolymorphicObject. This is impossible, since you cannot override a method template (it needs to be a template to accept a lambda) – that's where the compile-time and runtime parts of C++ clash. And there is simply no type in C++ that represents a function accepting any parameter (and knowing its type), which is a template by itself.
You can partially solve this by making the type of the lambda known to PolymorphicBase:
template <class Retriever>
class PolymorphicBase
{
public:
virtual void retrieve(Retriever func) = 0;
virtual ~PolymorphicBase() = default;
};
template <class Retriever, class T>
class PolymorphicObject : public PolymorphicBase<Retriever>
{
T value;
public:
PolymorphicObject(T value) : value(std::move(value))
{
}
void retrieve(Retriever func) override
{
func(value);
}
};
auto lambda = [](auto arg)
{
std::cout << arg << std::endl;
};
PolymorphicObject<decltype(lambda), int> obj(6);
PolymorphicBase<decltype(lambda)> &ptr = obj;
ptr.retrieve(lambda);
This is useful if you ever have only a single way to retrieve the value.
I don't think this is needed in most cases anyway. Usually you use a fixed set of types as the values, so you can use a variant there, or they all implement a common interface, or (as you've pointed out in the comments) you actually meant to move the type parameter from the method to the class (which allows you to check that all the types actually support the value earlier than originally).
However, I agree that in languages with generics/templates it is somewhat hard to have a method that can actually choose its result type in a generic fashion, without being controlled by outside parameters.

Get templated type of Base inside of class that owns instance of Derived

I would like to get the templated type of the base class inside of an object that owns an instance of the derived class. The code snippet below won't work because Base and its ArbitraryType can't be referenced through DerivedString. (line marked with the exclamation point). However, it can most definitely be inferred from the type of its own template (OneOfTheDerivedTypes). In my case, I intend for AnotherObject with a defined template to be inherited from, so I don't want to just hardcode the return type to GetSomethingFromThingy().
// -------------------
// Provided by my API:
// -------------------
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
};
template <typename OneOfTheDerivedTypes>
class AnotherObject<OneOfTheDerivedTypes> {
// Other functions that perform useful tasks are here so that
// classes that inherit from AnotherObject need not implement them.
void SomethingMagical();
// A function with a specific return type.
virtual DerivedString::Base::ArbitraryType GetSomethingFromThingy() = 0; /* ! */
protected:
OneOfTheDerivedTypes thingy;
};
// --------------------------------------
// Someone using my API would make these:
// --------------------------------------
class DerivedFloat : public Base<float> {
void DoSomething(float) override;
};
class DerivedString : public Base<string> {
void DoSomething(string) override;
};
class UsefulObject : public AnotherObject<DerivedString> {
// Knows the required return type of GetSomethingFromThingy() without
// needing to specify it as a template. Should throw compile-time error
// if you tried to override with a different return type. In other words,
// forces return type to be string because of use of DerivedString.
string GetSomethingFromThingy() override;
};
One solution to this is specify an additional template arg called ArbitraryType as seen below:
template <typename OneOfTheDerivedTypes, typename ArbitraryType>
class AnotherObject<OneOfTheDerivedTypes> {
virtual ArbitraryType GetSomethingFromThingy() = 0;
protected:
OneOfTheDerivedTypes thingy;
};
class UsefulObject<DerivedString, string> : public AnotherObject<DerivedString, string> {
string GetSomethingFromThingy() override;
};
The programmer then must specify both parameters where OneOfTheDerivedTypes is either DerivedFloat or DerivedString and ArbitraryType is float or string, respectively. Not a good solution because ArbitraryType is completely specified by the choice of OneOfTheDerivedTypes.
I think the extra template (ArbitraryType in AnotherObject) could be avoided by having Base return an instance of ArbitraryType in a public function (call it ReturnInstanceOfArbitraryType()) and use decltype(OneOfTheDerivedTypes::ReturnInstanceOfArbitraryType()) inside of AnotherObject. This seems inelegant because ReturnInstanceOfArbitraryType() is not useful otherwise (and must be public). Is this a case where the proper thing to do is to use a traits class? Is there a better solution? (Still getting the hang of some of this new C++11 stuff). Thanks!
Maybe I've misunderstood your question, but can't you just add a typedef to Base?
template <typename ArbitraryType>
class Base {
virtual void DoSomething(ArbitraryType);
using parameter_type = ArbitraryType;
};
And then you can refer to it:
template <typename OneOfTheDerivedTypes>
class AnotherObject {
// A function with a specific return type.
virtual typename OneOfTheDerivedTypes::parameter_type GetSomethingFromThingy() = 0;
};
And then the override in the derived type will enforce that the return types are the same (or covariant):
class UsefulObject : public AnotherObject<DerivedString> {
string GetSomethingFromThingy() override;
};
You could also add a static_assert if you want a more user-friendly error message:
class UsefulObject : public AnotherObject<DerivedString> {
using base_parameter_type = typename AnotherObject<DerivedString>::parameter_type;
static_assert(std::is_same<string, base_parameter_type>::value,
"mismatched parameter types");
string GetSomethingFromThingy() override;
};
If you can't modify the Base template it's also possible to detect the type using some metaprogramming. First, declare (but don't define) a function that can deduce the type T from Base<T>:
template<typename T> T* detect_base_parameter_type(Base<T>*); // undefined
Now define an alias template which takes one of the derived types as its template parameter, and uses the function above to find the template argument of its base-class:
template<typename DerivedT>
using base_parameter_t = typename std::remove_pointer<
decltype( detect_base_parameter_type(std::declval<DerivedT*>()) )
>::type;
This uses decltype to detect the return type of calling detect_base_parameter_type with a pointer to the derived type. That pointer will convert to a pointer to Base<T> (deducing whatever type T is for DerivedT) and the function's return type will be T*. Then we use remove_pointer to turn that into T.
Now you can use that alias template in your other classes:
template <typename OneOfTheDerivedTypes>
class AnotherObject {
// A function with a specific return type.
virtual base_parameter_t<OneOfTheDerivedTypes> GetSomethingFromThingy() = 0;
};
class UsefulObject : public AnotherObject<DerivedString> {
using base_parameter_type = base_parameter_t<DerivedString>;
static_assert(std::is_same<string, base_parameter_type>::value,
"mismatched parameter types");
string GetSomethingFromThingy() override;
};

C++ - Use Class Name As Function Parameter

Say I have list of of classes called ItemOne, ItemTwo, ItemThree and ItemFour, which are all subclasses of ItemBase.
I would like to have a constructor in another class called ItemGenerator that accepts the name of any of these classes. How would I do this?
ItemGenerator *someItem = new ItemGenerator(ItemThree);
Another option would be to pass a static function on one of these classes, but again, I have no idea how to do that.
ItemGenerator *someItem = new ItemGenerator(ItemOne::start());
Thanks.
You could use a template:
struct ItemBase {virtual ~ItemBase();};
struct ItemOne : ItemBase {};
struct ItemTwo : ItemBase {};
struct ItemThree : ItemBase {};
struct ItemFour : ItemBase {};
struct ItemGeneratorBase {
virtual unique_ptr<ItemBase> generate() {}
virtual ~ItemGeneratorBase() {}
};
template<typename Item>
struct ItemGenerator : ItemGeneratorBase {
virtual unique_ptr<ItemBase> generate() {
return unique_ptr<ItemBase>(new Item());
}
};
std::unique_ptr<ItemGeneratorBase> someItem(new ItemGenerator<ItemThree>());
Do you really want to pass the name, i.e. a string? Then you'd have to provide the Item*-classes with a corresponding function, e.g.
class ItemOne {
static std::string name();
};
ItemGenerator *someItem = new ItemGenerator(ItemThree::name());
Or are you looking for templates? You have different possibilities there: make a class template, maybe derived from an ItemGenerator base class:
class AbstractItemGenerator { /* ... */ };
template <class Item>
class ItemGenerator {
ItemGenerator();
};
ItemGeneratorBase *someItem = new ItemGenerator<ItemTwo>();
Or make only the construtor templated - you cannot explicitly specify the parameter, so use argumet deduction:
//take 1: use pointers
class ItemGenerator {
template <class Item>
ItemGenerator(Item* dummy);
};
ItemGenerator *someItem = new ItemGenerator((ItemFour*)NULL);
//take 2: use a tag struct
template <class I>
struct ItemTag{};
class ItemGenerator {
template <class Item>
ItemGenerator(ItemTag<Item> tag);
};
ItemGenerator *someItem = new ItemGenerator(ItemTag<ItemOne>());
I am not sure if one of these suits your needs. Maybe elaborate what you want to use this for.
Function cannot accept name of a class as a parameter, as class is not an object in C++.
But template-function can be parametrized by a class name.
Something like this:
template<class T>
ItemGenerator* ItemGeneratorFactory() { T::start(); ...}
ItemGenerator *someItem = ItemGeneratorFactory<ItemThree>();
As the other answers indicate, you can achieve using templates.
Just to offer another idea, you can pass a function pointer that creates an instance of whatever you want (or whatever it is you want to do with that class)
ItemGenerator(ItemClassPtr itemClassFn)
{
void * myObject = itemClassFn();
}
I'm a little rusty, but I'm pretty sure you could just put ItemBase in the constructor and it would accept all subclasses.
ItemGenerator::ItemGenerator(ItemBase base){\\do something with base
}
or, if that and using a template don't work, you could create multiple constructors:
ItemGenerator::ItemGenerator(ItemOne one){}
ItemGenerator::ItemGenerator(ItemTwo two){}
...
This is exactly what the Factory design pattern does.
Basically there is a static method in the ItemGenerator class that can return pointers to ItemBase objects, but can return pointers to Item1, Item2 etc depending on the parameters to the static method.
For instance, in the ItemGenerator class,
static ItemBase *Generate( <any parameter> )
{
switch (parameter)
{
case Value1: return new Item1();
...
...
}
}
It is difficult to find a solution to your problem without knowing the purpose of ItemGenerator.
As Mankarse says, one solution would be to use a template to pass your class to the generator.
Nevertheless, if ItemGenerator cannot be templated or if you do not want to use the templates here, you can still pass a function as you suggest by using either std::function or boost::function.
There are also some libraries that can help you to add reflexion to c++. I remember of CAMP but I do not know if it is still active. You may find a solution for your problem there.

How can I use templated generic constraints in C++/CLI

I'm having some trouble figuring out if I can use templated generic constraints in C++/CLI. here's an example
template<typename T>
public ref class wrapped
{
public:
T* t;
T doTthing(){return *t;}
};
Here's a simple templated managed class, wrapping an unmanaged type T. I can use this class as a constraint for a generic
// works
generic<class genclass> where genclass : wrapped<int>
public ref class testclass3
{
public:
genclass gc;
int test()
{
return gc->doTthing();
}
};
This works fine. What I can't figure out is how to preserve both the templating and the generic, i.e.
//Does Not Work!
template<typename T>
generic<class genclass> where genclass : wrapped<T>
public ref class testclass4
{
public:
genclass gc;
T test()
{
return gc->doTthing();
}
};
Is this kind of thing possible?
You can't mix templates with generics in the same declaration.
The class should either be templated or generic. See: Managed Templates
Templates are mush more expressive, so i would suggest you use them instead.
If you want to simulate a constraint (same technique would work in c++ by the way..) you could do:
template<class T, class GENCLASS>
public ref class testclass4
{
private:
typedef typename GENCLASS::wrapped<T> Constraint1;
public:
genclass gc;
T test()
{
return gc->doTthing();
}
};
If the class does not inherit from wrapped<T> then the typedef declaration will fail saying that "wrapped is not a member of GENCLASS".