How to create a "factory function" for a templated class? - c++

How would someone go about implementing a factory function for a templated class? Either my google searches aren't looking for the right thing, or I am misunderstanding the results. As an example:
template<typename T>
class Test
{
public:
T data;
void SizeOfData() { std::cout << "Data Size:" << sizeof(data) << "\n"; }
};
----this what I am trying to figure out how to do------
template <typename T>
Test<T> FactoryFunction(const std::string& type)
{
if(type == "int")
return Test<int>;
if(type == "long")
return Test<long long>;
}
----------------------------------------
int main()
{
auto a = FactoryFunction(std::string("int"));
auto b = FactoryFunction(std::string("long"));
a.SizeOfData();
b.SizeOfData();
a.data = 1;
b.data = 2;
}
Obviously, this code is all wrong - I am just trying to show what I want to do in theory. Can it be done? What do I look up in google - Factory functions to return templated classes? I am not even sure where to start. If someone could even point me in a direction - I really just want a function the returns the correct template instantiation based on the results of a switch or if/else list. I think conceptually the idea isn't hard, but implementing it is another thing - or I am really missing something.
Thanks for any help.

The type T of a templated function has to be determined in compile time.
Therefore you cannot do it the way you mentioned.
However - you can use the following pattern to achieve a similar result:
#include <assert.h>
class TestBase
{
public:
virtual void SizeOfData() = 0;
};
template<typename T>
class Test : public TestBase
{
public:
T data;
virtual void SizeOfData() override { std::cout << "Data Size:" << sizeof(data) << "\n"; }
};
std::unique_ptr<TestBase> FactoryFunction(const std::string& type)
{
if (type == "int")
return std::make_unique<Test<int>>();
if (type == "long")
return std::make_unique<Test<long long>>();
return nullptr;
}
int main()
{
auto a = FactoryFunction(std::string("int"));
assert(a);
auto b = FactoryFunction(std::string("long"));
assert(b);
a->SizeOfData();
b->SizeOfData();
return 0;
}
Some notes:
Each instance of Test (where T changes) is a differnt an unrelated class. In order to create a connection between them, I added a common base class.
In order to use polymorphism, you must use refernce semantics. Therefore the factory returns a pointer (in this case a std::unique_ptr).
The common method you need to invoke on all your Test objects (SizeOfData) became a virtual method in the base class.
This technique is actually related to the idiom of type erasure mentioned in the comments.
UPDATE: based on the comment below, I replaced using naked news with std::make_unique.
You can see more info why it is better here: Differences between std::make_unique and std::unique_ptr with new

Related

Cast structs with certain common members

Lets say I have 2 structs:
typedef struct
{
uint8_t useThis;
uint8_t u8Byte2;
uint8_t u8Byte3;
uint8_t u8Byte4;
} tstr1
and
typedef struct
{
uint8_t u8Byte1;
uint8_t u8Byte2;
uint8_t useThis;
} tstr2
I will only need the useThis member inside a function, but in some cases I will need to cast one struct or the other:
void someFunction()
{
someStuff();
SOMETHING MyInstance;
if(someVariable)
{
MyInstance = reinterpret_cast<tstr1*>(INFO_FROM_HARDWARE); //This line of course doesn't work
}
else
{
MyInstance = reinterpret_cast<tstr2*>(INFO_FROM_HARDWARE); //This line of course doesn't work
}
MyInstance->useThis; //Calling this memeber with no problem
moreStuff();
}
So I want to use useThis no matter what cast was done. How can this be done?
I want to avoid someFunction() to be template (just to avoid this kind of things)
Note tha questions like this have a kind of similar problem but the struct members have the same order
EDIT:
In RealLife these structs are way larger and have several "same named" members. Directly casting a uint8_t as reinterpret_cast<tstr1*>(INFO_FROM_HARDWARE)->useThis would be tedious and require several reinterpret_casts (althought it's a working solution for my question before this EDIT). This is why I insist on MyInstance being "complete".
This is what templates are for:
template<class tstr>
std::uint8_t
do_something(std::uint8_t* INFO_FROM_HARDWARE)
{
tstr MyInstance;
std::memcpy(&MyInstance, INFO_FROM_HARDWARE, sizeof MyInstance);
MyInstance.useThis; //Calling this memeber with no problem
// access MyInstance within the template
}
// usage
if(someVariable)
{
do_something<tstr1>(INFO_FROM_HARDWARE);
}
else
{
do_something<tstr2>(INFO_FROM_HARDWARE);
}
I want to avoid someFunction() to be template (just to avoid this kind of things)
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
The linked problem isn't an issue for your use case because the potential set of template arguments is a finite set. The very next FAQ entry explains how: Use explicit instantiations of the template.
as suggested by AndyG, how about std::variant (there's no mention of the c++ standard you are using so maybe a c++17 solution is ok - also worth using <insert other variant implementation> if no c++17 available).
here's an example
std::variant knows what type is stored in it and you can use visit anytime you wish to use any of the members in there (snippet here for clarity):
// stolen from #eerrorika (sorry for that :( )
struct hardware {
uint8_t a = 'A';
uint8_t b = 'B';
uint8_t c = 'C';
uint8_t d = 'D';
};
struct tstr1 {
uint8_t useThis;
uint8_t u8Byte2;
uint8_t u8Byte3;
uint8_t u8Byte4;
};
struct tstr2 {
uint8_t u8Byte1;
uint8_t u8Byte2;
uint8_t useThis;
};
// stuff
if(true)
{
msg = *reinterpret_cast<tstr1*>(&hw);
}
else
{
msg = *reinterpret_cast<tstr2*>(&hw);
}
std::visit(overloaded {
[](tstr1 const& arg) { std::cout << arg.useThis << ' '; },
[](tstr2 const& arg) { std::cout << arg.useThis << ' '; }
}, msg);
EDIT: you can also do a variant of pointers
EDIT2: forgot to escape some stuff...
Using virtual dispatch is usually not what you want when mapping to hardware but it is an alternative.
Example:
// define a common interface
struct overlay_base {
virtual ~overlay_base() = default;
virtual uint8_t& useThis() = 0;
virtual uint8_t& useThat() = 0;
};
template<class T>
class wrapper : public overlay_base {
public:
template<class HW>
wrapper(HW* hw) : instance_ptr(reinterpret_cast<T*>(hw)) {}
uint8_t& useThis() { return instance_ptr->useThis; }
uint8_t& useThat() { return instance_ptr->useThat; }
private:
T* instance_ptr;
};
With that, you can declare a base class pointer, assign it, and use after the if statement:
int main(int argc, char**) {
std::unique_ptr<overlay_base> MyInstance;
if(argc % 2) {
MyInstance.reset( new wrapper<tstr1>(INFO_FROM_HARDWARE) );
} else {
MyInstance.reset( new wrapper<tstr2>(INFO_FROM_HARDWARE) );
}
std::cout << MyInstance->useThis() << '\n';
std::cout << MyInstance->useThat() << '\n';
}
Demo
Explanation regarding my comment: "It works, but unless the compiler is really clever and can optimize away the virtual dispatch in your inner loops, it's going to be slower than if you actually take the time to type cast":
Think of virtual dispatch as having a lookup table (vtable) used at runtime (which is often what actually happens). When calling a virtual function, the program has to use that lookup table to find the address of the actual member function to call. When it's impossible to optimize away the lookup (as I made sure in my example above by using a value only available at runtime) it does take a few CPU cycles extra compared to what you'd get by doing a static cast.
A simple reference to the struct member might be what you need:
uint8_t &useThis=SomeVariable
?reinterpret_cast<tstr1*>(INFO_FROM_HARDWARE)->useThis
:reinterpret_cast<tstr2*>(INFO_FROM_HARDWARE)->useThis;

How to use a compile-time interface with a runtime type?

I have a function that takes a T and calls specific functions on the supplied object. Until now it was used from compile-time objects, so all was great. Minimal example:
#include <iostream>
struct A {
void fun() const { std::cout << "A" << std::endl; }
};
struct B {
void fun() const { std::cout << "B" << std::endl; }
};
template<class T>
void use_function(const T& param) {
param.fun();
}
int main() {
use_function(A{}); // "A"
use_function(B{}); // "B"
return 0;
}
Now I'm trying to use that use_function() with objects that get created at runtime and having a hard time. I can't use std::variant or std::any since I need to supply the type as template parameter for their access functions - although all their variants fulfil the function interface. Example for a (failing) variant approach:
using var_type = std::variant<A, B>;
struct IdentityVisitor {
template<class T>
auto operator()(const T& alternative) const -> T {
return alternative;
}
};
int main() {
var_type var = A{};
// error C2338: visit() requires the result of all potential invocations to have the same type and value category (N4828 [variant.visit]/2).
use_function(std::visit(IdentityVisitor{}, var));
return 0;
}
What is possible is directly calling the function with an appropriate type like this:
if (rand() % 2 == 0)
use_function(A{});
else
use_function(B{});
just storing it in between is what I can't get working.
I understand on a technical level but having trouble coming up with an elegant solution. Is there one? I know that I could rewrite the objects with even a lightweight inheritance - but was trying to see if it's feasible to avoid it altogether, even if just as an exercise to avoid OOP in favor of templates and concepts. I feel like variants should be working with this, but apparently not.
std::visit([](auto const& x) { use_function(x); }, var);
If overload sets were objects, you could pass use_function to std::visit directly. Because they aren't, you need to wrap it in something that will be instantiated as a call to the right overload.
std::visit([](auto const& x) { use_function(x); }, var);

how to find type of an object contained in a vector of polymorphic base class?

let's assume I have a super polymorphic base class Shape where many other shape classes are derived from it.
now if I have a vector of Shape pointers that contains a pointer to a list of different shape types like this:
vector<Shape*> p; // p contains pointer to many different shape objects
I know to have access to methods and members of each shape in vector p, I need to use dynamic_cast.
but what if I don't know what vector p actually contains at runtime? how can i safely find the type of an object contained in vector p at runtime?
i also know i can check if casting by dynamic_cast returns NULL or not for success. but does that mean to find the actual type of my shape object in vector p I have to do something like this:
if (dynamic_cast<Circle*> p[i] !=NULL){
// do stuff
}
else if (...) {
}
and repeat this pattern for all other shape types?
but this becomes cumbersome if I have 100 possible shapes. is there any better way to achieve this at rumtime?
ps- consider following scenario:
lets say I need to iterate through the Shape* vector and for example put all the circle objects in a separate vector and vector etc ... now i need to know the actual type of the objects. checking the return if typeid and dynamic_casts for many shapes is not practical.
You can use typeid in typeinfo header.
See for instance this question: How to determine actual object type at runtime in C++;
However, the actual question is "why do you need to know the actual type of your object?": that this is AFAIK not that frequent to need such a functionnality, since polymorphimsm already allows for managing a vast majority of use cases.
I know to have access to methods and members of each shape in vector
p, I need to use dynamic_cast.
No, not necessarily!
In your case, maybe the following is enough, assuming Shape has an area method, (re)defined in Circle and Rectangle (who both extend the Shape class):
std::vector<Shape*> shapes;
Rectangle rect(...);
Circle circle(...);
shapes.push_back( &rect );
shapes.push_back( &circle );
shapes[0]->area(); // --> calls Rectangle::area()
shapes[1]->area(); // --> calls Circle::area()
I came up with solution that I'm not really proud of, but maybe it will be helpfull in creating better one.
Key thing I was trying to achieve was to get rid of explicit dynamic_cast and got this one working. There is still a need to name your derieved type twice though.
Also, it uses std::function which is told to be slow. C++14 required.
I believe there is a way to do it with just smart usage of templates. Or at least get rid of type_switch<A>::cast<B> lanes. Anyway, the code:
#include <iostream>
#include <functional>
#include <typeindex>
#include <unordered_map>
// Basic inheritance cases
struct A
{
virtual void foo() = 0;
};
struct B : public A
{
void foo() override { }
void bfoo() {
std::cout << "B specific\n";
}
};
struct C : public A
{
void foo() override { }
};
template <typename T>
struct type_switch
{
using Func = std::function<void(T&)>;
using Pair = std::pair<std::type_index, Func>;
using Map = std::unordered_map<std::type_index, Func>;
Map map;
type_switch(std::initializer_list<Pair> l) : map(l.begin(),l.end())
{
}
void call(T& a)
{
map[typeid(a)](a);
}
// allows for "oneliner", without explicit 'call', but it could end in creation of
// new type_switch on every loop iteration etc.
type_switch(T&a, std::initializer_list<Pair> l) : type_switch(l){
call(a);
}
template <typename T2>
static Func cast(std::function<void(T2&)> f)
{
static_assert(std::is_base_of<T, T2>::value, "Invalid cast operation on functors, T2 is not base of T");
// lot of functor copyings...
return[f = std::move(f)](T& t) {
f(static_cast<T2&>(t));
};
}
};
int main()
{
B b;
C c;
int local = 0;
type_switch<A> sw = {
{ typeid(B), type_switch<A>::cast<B>( [&local](auto& a) { // auto will deduce into B! No explicit casting
std::cout << "Handle b, local value is " << local << '\n';
a.bfoo(); // B specific
local++; // some outer scode operation
}) } ,
{ typeid(C), type_switch<A>::cast<C>([&local](auto& a) { // auto will deduce into C! No explicit casting
std::cout << "Handle c, local value is " << local << '\n';
local++; // some outer scode operation
})
},
/* // this one would trigger static_assert
{ typeid(int), type_switch<A>::cast<int>([&local](auto& a) { // auto will deduce into C! No explicit casting
std::cout << "Handle int, local value is " << local << '\n';
local++; // some outer scode operation
})
},*/
};
sw.call(b);
sw.call(c);
return 0;
}

C++ Returning Multiple Types as Reference

Ok so I'm trying to setup a template method that returns a reference of an undetermined type based on a parameter request. Everything looks fine but it keeps telling me that no overloaded method of the provided template method exists when I call it. The code looks something like this:
class IObj {
public:
int id;
}
class ObjOne : public IObj {}
class ObjTwo : public IObj {}
class ObjThree : public IObj {}
enum ObjectTypes {
O1Type,
O2Type,
O3Type
}
class ObjManager {
public:
std::vector< std::unique_ptr<ObjOne> > O1Holder;
std::vector< std::unique_ptr<ObjTwo> > O2Holder;
std::vector< std::unique_ptr<ObjThree> > O3Holder;
ObjManager() {}
template <class T>
T& GetObject(int oID, ObjectTypes oType) {
if(oType == ObjectTypes::O1Type) {
for(int i = 0; i < O1Holder.size(); i++) {
if(O1Holder[i]->id == oID) {
return *O1Holder[i];
}
}
}
else if(oType == ObjectTypes::O2Type) {
for(int i = 0; i < O2Holder.size(); i++) {
if(O2Holder[i]->id == oID) {
return *O2Holder[i];
}
}
}
else if(oType == ObjectTypes::O3Type) {
for(int i = 0; i < O3Holder.size(); i++) {
if(O3Holder[i]->id == oID) {
return *O3Holder[i];
}
}
}
}
}
int main() {
std::unique_ptr<ObjManager> oManager(new ObjManager());
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type);
return 0;
}
Everything works fine, and I can make a method that returns a reference to the object stored in the vectors if I return their specific type, but I'm trying to reduce the redundancy of making many functions to return each different type. So I wanted to make a templated method that would return an object type based on which ever type I requested.
It's not giving me any errors it just keeps underlining the -> in the expression oManager->GetObject, and tells me there is no overloaded method for the template method call. Specifically it states "no instance of function template 'ObjManager::GetObject' matches the argument list, argument types are (int, ObjectTypes)" even though I'm passing an integer and ObjectTypes:: into the function's parameter list. I've looked all over for an answer to this but have not been able to find a similar situation to draw experience on.
EDIT: Sorry should have specified that this is a precursor to a vast list of vectors, I just put 3 of them for simplicity. That's why I'm trying to make a single function that can handle the return of different types so that I don't have to make a return function for every vector I create. And the purpose of returning a reference to the specified type is because each derived type will have unique data that is not in the base class, so I'm pulling the objects for editing.
As #tobi303 commented, you should definetly use the template Parameter T in your GetObject class. Then you would actually avoid repeating yourself as the Compiler will generate the code for you that you have repeated 3 times
template <class T>
T& GetObject(int oID) {
for(int i = 0; i < OHolder<T>.size(); i++) {
if(OHolder<T>[i]->id == oID) {
return *OHolder<T>[i];
}
}
While you would have to define a OHolder Template function, too.
It is not possible to change the return type of a function based on runtime information (such as your parameters), because they are obviously unknown to the compiler.
If you will always know at compile time which object type you are going to choose, you can use a trick:
Step 1: Turn your enum into a couple of empty structs:
struct O1Type {};
struct O2Type {};
struct O3Type {};
Step 2: Instead of using else ifs, use function overloading:
ObjOne& GetObject(int oID, O1Type) {/* TODO*/}
ObjTwo& GetObject(int oID, O2Type) {/* TODO*/}
ObjThree& GetObject(int oID, O3Type) {/* TODO*/}
You can now use
ObjOne& a = oManager->GetObject(0, O1Type());
(or, even better auto& a = oManager->GetObject(0, O1Type());)
You seem to be trying to use both run-time polymorphism AND the compile-time (template) polymorphism. It doesn't work this way. You cannot return multiple types from the SAME METHOD.
What you probably want to do is to either define a method like #yussuf described, or to fully start using run-time polymorphism - in which case you don't need three containers, and the type becomes part of the object ID.
I concur with #yussuf's approach. Just do that, it probably will solve your problem.
I would also recommend to use a hash / map instead of performing linear search, but this is a different story...
Root cause
Template argument type deduction can't be solely based on the return type of the function.
On the way to a solution
You could therefore add a dummy function argument to transfer the type information:
template <class T>
T& GetObject(int oID, ObjectTypes oType, T&x) {
...
}
and in main():
ObjOne& a = oManager->GetObject(0, ObjectTypes::O1Type, a);
Then the template type can be deduced.
But this will not solve your problem. This type deduction is at compile time, so that all the possible returns of the function should return the same type (or something that can be converted to it).
This is not the case of your code, which will lead to other compilation errors (see online failure).
The solution
The only workable solution is that you determine the common denominator to return. Make the function a non-template function returning an IObj&:
IObj& GetObject(int oID, ObjectTypes oType) {
...
}
You should then manage the return object as a polymorphic obhect as well. As the return is by reference, this is fine (i.e. no slicing occurs). The returned reference will really refer to the object returned, whatever its derived type could be. But you'd have to redesign your calling code for polymorphism:
IObj& a = oManager->GetObject(0, ObjectTypes::O1Type);
Online demo
But this is somewhat clumsy because you indicate in an enum the expected type, but then end with a reference to a parent that you can't handle so easily.
Conclusion
As you indicate in the function the expected return type, you'd better go for the solution in Yussuf's rexcellent answer, but applying the technique of the dummy argument for type deduction.
Ok so after much research, I have determined the best way to accomplish this is to create a custom container class like so:
#include <vector>
#include <memory>
class Base {
public:
int ID;
Base(int id) { ID = id; }
}
class A : public Base {
public:
int X;
A(int id) : Base(id) {}
}
class B : public Base {
public:
int Y;
B(int id) : Base(id) {}
}
template <class T>
class MyContainer {
private:
std::vector<std::unique_ptr<T>> internalContainer;
public:
MyContainer() {}
~MyContainer() {}
void CreateItem(int id) {
std::unique_ptr<T> newItem(new T(id));
internalContainer.push_back(std::move(newItem));
}
T& GetItem(int id) {
for(std::vector<std::unique_ptr<T>>::iterator it = internalContainer.begin(); it!= internalContainer.end(); ++it) {
if((*it)->ID == id) {
return **it;
}
}
}
}
int main() {
MyContainer<A> AList;
MyContainer<B> BList;
AList.CreateItem(0);
BList.CreateItem(0);
A& AOne = AList.GetItem(0);
B& BOne = BList.GetItem(0);
AOne.X = 10;
BOne.Y = 20;
std::cout << std::to_string(AOne.X) << "\n";
std::cout << std::to_string(BOne.Y) << "\n";
}
Let me know your opinions on if this is acceptable or if it can be improved! :)

Subclass lookup table

I have a very simple C++ lookup table for dispatching commands:
template <class T> Action* CreateAction(Command *c)
{
return new T(c);
}
typedef Action* CreateActionFunc(Command *c);
typedef struct ActionTable {
string name;
CreateActionFunc *func;
} ActionTableEntry;
vector<ActionTableEntry> GlobalActionTable = {
{ "quit" , &CreateAction<DoQuit> },
};
This works fine, but I would rather have my CreateAction function construct the new object on the stack and return it by value. But when I write this:
template <class T> T CreateAction(Command *c)
{
return T(c);
}
typedef Action CreateActionFunc(Command *c);
Then the program will no longer compile. First I get an error that an abstract class cannot be instantiated (on the typedef line) and also an error that the initialization list for the table doesn't match the type of the vector.
There is a very similar question here but every answer uses new in the factory methods, which is explicitly what I'm trying to avoid. How can this be done?
You can't use polymorphism with objects by value.
Need to be pointers or reference.
I'm guessing here you have an Action interface (so an abstract class), so you can't create an object of this dynamic type. All you can do is send a pointer of type Action with a dynamic type of a Derived Class (so what you are already doing i assume).
You could create a value object of a derived type on the stack and return a reference on the Base class and still use polymorphism, but then you'll need to address the lifetime of the Derived object problem.
The Action sub class has more information than the Action class itself - pointers to a table of it's member function, data members etc. There's not enough memory to hold this information if you return by value. Something called slicing would occur.
This answer explains it better.
How about doing something like this instead:
class Action {
void do_something(Command& params) = 0;
};
class SayHello {
void do_something(Command& params) { std::cout << "Hi!" << std::endl; }
}
class SayBye {
void do_something(Command& params) { std::cout << "Goodbye." << std::endl; }
}
.....
SayHello hello;
SayBye bye;
Quit quit;
std::map<string, Action&> action_table = {
{"hello", hello},
{"bye", bye},
{"quit", quit},
};
....
Action& getAction(Command* command) {
...;
return action_from_map;
}
This creates the action once, and returns them by reference.
What about something simple like this?
std::map<string, std::function<void(CommandArgs const&)>> action_table =
{
{"hello", [](CommandArgs const& args) { /* do something */ }},
};