Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have a class named Creation in both Creation.cc and Creation.h, and there are bunch of createA, createB, createC...etc. functions inside this class, all of them will return a pointer type.
I have a lot of modelA.cc, modelB.cc, modelC.cc ...etc. files, and all of them have included Creation.h.
Since whenever I make a new model x (make a new modelx.cc), I need to add the corresponding createx in Creation.h, which will make all model.cc files being compiled again.
All the createA, createB, createC functions have same parameter list but different input values and implementation, which are based on their model.cc.
My goal is that I don't want to recompile all model.cc when adding a new createx function.
Thanks.
A common strategy is to have the factory contain a registration method. Once a class is registered then a call is made to the factory to get an actual instance.
The C++17 example below allows sub-classes of the 'interface' to have different parameters in the call for creation. 'createInstance' is tasked with constructing an instance for a particular class.
The Any class was taken from here. As noted in the link, the createInstance call is quite particular about the input arguments matching the method signature.
#include <iostream>
#include <functional>
#include <map>
#include <string>
#include <any>
#include <functional>
#include <map>
#include <string>
#include <iostream>
struct interface
{
};
template<typename Ret>
struct AnyCallable
{
AnyCallable() {}
template<typename F>
AnyCallable(F&& fun) : AnyCallable(std::function(fun)) {}
template<typename ... Args>
AnyCallable(std::function<Ret(Args...)> fun) : m_any(fun) {}
template<typename ... Args>
Ret operator()(Args&& ... args)
{
return std::invoke(std::any_cast<std::function<Ret(Args...)>>(m_any), std::forward<Args>(args)...);
}
std::any m_any;
};
struct factory
{
std::map<std::string, AnyCallable<interface>> registry;
void registerClass(std::string const & class_name, AnyCallable<interface> function)
{
registry[class_name] = function;
}
template<typename ... Args>
interface createInstance(std::string const & class_name, Args && ... args)
{
if(registry.find(class_name) == registry.end())
{
throw "No class found";
}
return registry[class_name](std::forward<Args>(args)...);
}
};
struct A:public interface
{
A()
{
std::cout << "Create A" << std::endl;
}
static interface createInstance(int t)
{
return A();
}
static void registerWithFactory(factory& f)
{
f.registerClass("A",&createInstance);
}
};
struct B:public interface
{
B()
{
std::cout << "Create B" << std::endl;
}
static interface createInstance(std::tuple<int, double> t)
{
return B();
}
static void registerWithFactory(factory& f)
{
f.registerClass("B",&createInstance);
}
};
int main(int argc, char* argv[])
{
factory f;
A::registerWithFactory(f);
B::registerWithFactory(f);
try {
interface a = f.createInstance("A",1);
interface b = f.createInstance("B",std::tuple{1,1.0});
interface c = f.createInstance("C");
}
catch(...)
{
std::cout << "createInstance failed" << std::endl;
}
return 0;
}
All the members of the factory will descend from 'interface'. The 'factory' will allow registration of new class that are not yet created. In the example A and B exists but C does not. In the future C can be added without recompiling the existing code.
There are a variety of patterns that expand on this theme.
Related
I want to store 6 pointers to objects. But the Pointers can be in any order and point to different instances of (12) subclasses of one superclass, so they are possibly all of different types.
Arrays and such don't work, because the superclass is virtual.
Vectors and Tuples don't work, because the datatypes are of no specific order and are not known at compile time.
Im fairly new to C++ and I'm running out of Ideas.
Here some code to elaborate the problem:
baseclass{
getfoobar()=0;
}
subclass1{
getfoobar(){...}
}
subclass2{
getfoobar(){...}
}
---
#include <otherclasses.h>
memoryclass{
baseclass mem[6];
}
is basically what im trying.
You CAN create a vector of superclass pointers. It will achieve what you want, as it will call the overwritten function. This is of course assuming you are talking about inheritance, like:
#include <vector>
using type = ????;
class A {
virtual type foo() = 0;
}
class B : A {
type foo() override { ... }
}
class C : A {
type foo() override { ... }
}
int main(){
std::vector<A*> arr;
arr.push_back(new B);
arr.push_back(new C);
}
Now if I misunderstood and this doesn't work for some reason (i.e. they just share the function and are not actually related classes), you can do something like this, but it is not very nice:
#include <concepts>
#include <vector>
#include <functional>
using type = ?????;
template <class T> requires requires(T t){
{ t.foo() } -> std::same_as<type>;
}
std::function<type()> getFunction(T* t){
return [t](){ return t->foo(); };
}
int main(){
std::vector<std::function<type()>> arr;
arr.push_back(getFunction(new B));
arr.push_back(getFunction(new C));
}
I don't recommend this over the first option unless you have very good reason to do this.
Note: Since you didn't specify return type I winged it with ?????
Also: In the second you can replace template<class T> requires ... std::function<type()>, with just template<class T> std::function<type()>, if the compiler doesn't like #include <concepts>
You can try std::set<Superclass*>. Use pointers to your base superclass instead pointers to particular subclasses.
Actually I used std::shared_ptr<> smart pointer template to avoid raw memory management.
Example code:
#include <cstdlib>
#include <string>
#include <sstream>
#include <set>
#include <memory>
#include <iostream>
class baseclass {
public:
virtual std::string getfoobar() = 0;
};
typedef std::shared_ptr<baseclass> baseclass_ptr;
class subclass1 : public baseclass{
public:
std::string getfoobar() override {
return "from subclass1";
}
};
class subclass2 : public baseclass{
public:
std::string getfoobar() override {
return "from subclass2";
}
};
int main(int argc, char** argv) {
// Use current time as seed for random generator
std::srand(static_cast<unsigned>(std::time(nullptr)));
std::set<baseclass_ptr> container;
// Randomly generate number of elements
const int random_count = std::rand() % 10 + 1;
for (int i = 0; i < random_count; ++i) {
// Randomly create subclass1 or subclass2
if (std::rand() % 2) {
container.insert(std::make_shared<subclass1>());
}
else {
container.insert(std::make_shared<subclass2>());
}
}
// Iterate resulting container
std::cout << "size = " << container.size() << std::endl;
for (auto iterator : container) {
std::cout << "getfoobar(): " << iterator->getfoobar() << std::endl;
}
return 0;
}
I have a bit of trouble understanding a std::bind call.
In the following example:
#include <functional>
#include <iostream>
#include <memory>
class Notifier
{
public:
Notifier(std::function<void(Notifier&)> on_notify)
:on_notify_(on_notify)
{ }
void notify()
{
if (on_notify_)
on_notify_(*this);
}
std::function<void(Notifier&)> on_notify_;
};
struct Manager
{
Manager()
{
n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this));
}
void trigger()
{
std::cout << "notified" << std::endl;
}
std::unique_ptr<Notifier> n_;
};
int main()
{
Manager s;
s.n_->notify();
}
I don't understand how on_notify_(*this); calls back the functor with a Notifier& parameter, but the functor created by bind doesn't specify it.
The calls result correctly to the void notify() method, but I don't understand what exactly will be the functor created by bind to result in this.
If I were to write a lambda instead, I would need to specify the parameter, otherwise it would compile.
What kind of operation does bind here behind my back? :-)
std::bind basically ignores the invalid given argument according to this.
If some of the arguments that are supplied in the call to g() are not matched by any placeholders stored in g, the unused arguments are evaluated and discarded.
It might surprise you that when even more absurd arguments are provided, the binded functor can still successfully reach Manager::trigger() as follows:
#include <functional>
#include <iostream>
#include <memory>
// Some classes that have nothing to do with on_notify_
class AAA {};
class BBB {};
class Notifier
{
public:
Notifier(std::function<void(AAA&, BBB&)> on_notify)
:on_notify_(on_notify)
{ }
void notify()
{
if (on_notify_)
{
// Arguments not matching.
AAA a{};
BBB b{};
// Invoke with them.
on_notify_(a, b);
}
}
std::function<void(AAA&, BBB&)> on_notify_;
};
struct Manager
{
Manager()
{
n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this));
}
void trigger()
{
std::cout << "it's also notified!" << std::endl;
}
std::unique_ptr<Notifier> n_;
};
int main()
{
Manager s;
s.n_->notify();
}
Live demo is here.
The idea is identical to the generic version of GetComponent() in Unity. But I'm currently stumbling on the following template issue:
template<class T> std::shared_ptr<T> MyClass::GetMyComponent()
{
for (int i = 0; i < _baseTypeList.size(); i++)
{
auto base = _baseTypeList[i];
T* check = dynamic_cast<T*>(base.get());
if (check)
{
return std::static_pointer_cast<T>(base);
}
}
return std::shared_ptr<T>(nullptr);
}
where _baseTypeList is a std::vector<std::shared_pntr{MyBaseType}> types.
In this function, I am iterating over a list of components to find if there is one that matches the type I'm asking for. if there is one, return the component cast to that type. Otherwise return a nullptr.
However, when I call this function from outside code, I get the following error:
error C2680: 'MyType*' : invalid target type for dynamic_cast
where MyType is some class that derives from component.
When I put #include "MyType.h" in the header it compiles just fine but without it it gives this error and doesn't compile.
This means I cannot use it in other classes without modifying the header file this template class resides in, which will be a problem for me.
Is there a way I can achieve simular results without having to #include every single header of the type I pass in the template for?
[EDIT]
For clarity, consider a person using my library, he creates a type
"Foo : MyBaseType" where MyBaseType has a virtual method "Update" that is called every frame.
any instance of class MyBaseType (including Foo) is to be managed by this library, and have update called every frame.
This library thus has a large list of "MyBaseType" objects. But has no knowledge of the actual type they are, just that they derive from "MyBaseType", so it can call Update() on them.
If I need a specific type the library needs to be able to search for it in this list and return it.
I would like this "search" to happen in the library itself, so I do not have to expose the list, and write a new "search" method for every type that derives from "MyBaseType"
[FINAL]
It turned out I messed up the include order in my project.
a minimal example of what I was trying to do would be:
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <memory>
#include "vector"
class MyBaseClass
{
virtual void Update(){};
};
class MyLibrary
{
public:
template<class T> std::shared_ptr<T> GetComponent();
std::vector<std::shared_ptr<MyBaseClass>> list;
};
template<class T> std::shared_ptr<T> MyLibrary::GetComponent()
{
static_assert(std::is_base_of<MyBaseClass, T>::value, "T1 is no subclass of ModelComponent");
for (unsigned int i = 0; i < list.size(); i++)
{
auto comp = list[i];
T* check = dynamic_cast<T*>(comp.get());
if (check)
{
return std::static_pointer_cast<T>(comp);
}
}
return std::shared_ptr<T>(nullptr);
}
class MyClass : public MyBaseClass
{
void Update() override;
};
void MyClass::Update()
{
}
int _tmain(int argc, _TCHAR* argv[])
{
MyLibrary lib;
lib.list.push_back(std::make_shared<MyClass>());
auto var = lib.GetComponent<MyClass>();
std::cout << (var ? "var is object" : "var is not") << std::endl;
while (true)
{
}
return 0;
}
which works as expected.
The primary issue was that the compiler gave an error in the "GetMyComponent" function, so I found a usage of it that did everything as suggested.
But it turned out there was a second usage that did not have the definition of "MyClass" before calling it (but didn't give an error, as it was forward declared in its header file).
You don't need the definition of possible T types included into your header. You do need the relevant one defined in the translation unit in which the template is expanded:
// client.cpp
#include <myclass.h>
#include <foo.h> // defines class Foo
void f(MyClass *p)
{
auto c = p->GetMyComponent<Foo>();
c->foobar();
}
I'm trying to wrap std::packaged_task inside another class in order to be used together with a task scheduler.
At the moment I got it all working except std::future support. To get std::future support I figured out I need to use std::packaged_task for the get_future() function that it provides.
I've been trying whole day all sorts of ways to get this to work, but I seem to be unable to properly declare and initialise the packaged_task using the return value from a std::bind. I have tried to decipher the implementations of all the related libstdc++ functions such as std::async, std::future, std::thread etc but with no luck.
The following code is the implementation of both the not working version and the working one. To get it to work uncomment the two /* --- WORKS*/ and comment the other related line.
#include <vector>
#include <deque>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <iostream>
#include <chrono>
#include <functional>
#include <windows.h>
class task
{
private:
struct task_implementation_base
{
virtual void execute() = 0;
};
template <class callable>
struct task_implementation : public task_implementation_base
{
task_implementation(callable&& f) : /*m_task(std::forward<callable>(f)) WORKS*/m_task(f) { }
void execute() { m_task(); }
//callable m_task; // WORKS
std::packaged_task<typename result_of<callable>::type> m_task;
};
template <class callable>
std::shared_ptr<task_implementation<callable>> make_routine(callable&& f)
{
return std::make_shared<task_implementation<callable>>(std::forward<callable>(f));
}
public:
template <class callable, class... arguments>
task(callable&& f, arguments&&... args) : m_function(make_routine(std::bind(std::forward<callable>(f), std::forward<arguments>(args)...))) {}
void operator()() { run(); }
void run() { m_function->execute(); }
private:
std::shared_ptr<task_implementation_base> m_function;
};
int testint(int i)
{
std::cout << "test6" << " :: ran from thread " << std::this_thread::get_id() << "\n";
fflush(stdout);
return i+100;
}
void test(const char* text)
{
std::cout << text << " :: ran from thread " << std::this_thread::get_id() << "\n";
fflush(stdout);
}
class testclass
{
public:
void print1() { test("test3"); }
void print2() { test("test4"); }
void print3(const char* text) { test(text); }
};
int main()
{
testclass testclass1;
testclass* testclass2 = new testclass;
task test1(test, "test1");
task test2([]() { test("test2"); });
task test3(&testclass::print1, &testclass1);
task test4(&testclass::print2, &*testclass2);
task test5(&testclass::print3, &*testclass2, "test5");
task test6(&testint, 1);
test1();
test2();
test3();
test4();
test5();
test6();
Sleep(2000);
return 0;
}
I'm thinking the problem is typename result_of<callable>::type. I'm guessing it doesn't properly evaluates to the return type of the callable function.
I'm using c++ (Built by MinGW-builds project) 4.8.0 20121225 (experimental) on a Windows 8 64bit. I'm suspecting the errors are irrelevant since I guess I'm just simply trying to get this work the wrong way but here is a pastebin for the errors anyway: errors
std::packaged_task not only takes the result type of the invoked function as a template argument but also the types of the arguments you are passing to the to be invoked function.
You can define them as follows:
// somewhere
int foo(bool, int);
// somewhere else
std::packaged_task<int(bool, int)> p(foo);
To fix your code you need to add two empty parenthesis pairs. What I explained above also applies to std::result_of.
std::packaged_task<typename std::result_of<callable()>::type()> m_task;
It is only response to main topic question. "How to implement"
Example short implementation:
template <typename Signature> /// <---- 1
class Task;
template <typename Res, typename... ArgTypes>
class Task<Res(ArgTypes...)> /// <---- 2
{
public:
template <typename Function>
explicit Task(Function&& callback)
: _task{std::forward<Function>(callback)}
{ }
void execute(ArgTypes... args) noexcept(false)
{
//...
_task(std::forward<ArgTypes>(args)...);
}
private:
std::packaged_task<Res(ArgTypes...)> _task;
};
Not sure why step 1 & 2 are required but I did the same as in lib implementation. Maybe someone could extend this response.
The goal of this project is to create a library for distribution. In the past, I used forward declares so I didn't have to distribute a bunch of header files along with the libraries. However, I'm now trying to eliminate code duplication by switching to templates and am running into some issues.
First, a simple example project showing what is currently working:
//LibraryDep1.h
class LibraryDep1
{
public:
LibraryDep1(void) {};
virtual ~LibraryDep1(void) {};
template <typename T>
int TestFunction(T value)
{
std::cout << value << std::endl;
return 0;
}
};
//LibraryInclude.h
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
int TestFunction(int value);
int TestFunction(std::string value);
};
//LibraryInclude.cpp
#include "LibraryInclude.h"
#include "LibraryDep1.h"
LibraryInclude::LibraryInclude(void)
{
this->mLibDep1 = new LibraryDep1();
}
LibraryInclude::~LibraryInclude(void)
{
delete this->mLibDep1;
}
int LibraryInclude::TestFunction(int value)
{
return this->mLibDep1->TestFunction(value);
}
int LibraryInclude::TestFunction(std::string value)
{
return this->mLibDep1->TestFunction(value);
}
//main.cpp
#include <tchar.h>
#include "LibraryInclude.h"
int _tmain(int argc, _TCHAR* argv[])
{
LibraryInclude inclLibrary;
inclLibrary.TestFunction(77);
inclLibrary.TestFunction("test");
}
This gives the expected output of:
77
test
However, the overloads of LibraryInclude::TestFunction could be replaced with a template function to further reduce code duplication:
//LibraryInclude.h
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
template <typename T>
int TestFunction(T value) {
return mLibDep1->TestFunction(value);
}
};
The problem now is that I'm using mLibDep1 without including the full implementation giving me an undefined type compilation error. Meaning that I need to #include "LibraryDep1.h" in LibraryInclude.h, thus requiring me to distribute both LibraryInclude.h and LibraryDep1.h with my library. This is a simple example, the real project has many header files that would need to be distributed if I were to switch to using the templated version of LibraryInclude.
My question is, is there any way to avoid having to distribute a bunch of include files with my library and eliminate code duplication? Or, am I better off just overloading for all known types (drastically reducing library flexibility) in the distributed header file and keeping the templates in only the underlying classes?
No. There is currently no way to do what you want. When compiler vendors start implementing the 'export' keyword you'll be in luck. Currently I only know of Comeau doing so. This keyword has been around for years so I wouldn't hold my breath until the rest implement it.
A very limited and ugly solution would be:
//LibraryDep1.h
#pragma once
#include <iostream>
class LibraryDep1
{
public:
LibraryDep1(void) {};
virtual ~LibraryDep1(void) {};
template <typename T>
int TestFunction(T value)
{
std::cout << value << std::endl;
return 0;
}
};
//LibraryInclude.h
#pragma once
class LibraryDep1; //forward declare
class LibraryInclude
{
private:
LibraryDep1* mLibDep1;
public:
LibraryInclude(void);
virtual ~LibraryInclude(void);
template <typename T>
int TestFunction(T value);
};
//LibraryInclude.cpp
#include "LibraryInclude.h"
#include "LibraryDep1.h"
#include <string>
LibraryInclude::LibraryInclude(void)
{
mLibDep1 = new LibraryDep1();
}
LibraryInclude::~LibraryInclude(void)
{
}
// only to save some typing when only forwaring calls
#define LI_TESTFUNCTION( TYPE ) \
template<> \
int LibraryInclude::TestFunction<TYPE>( TYPE value ) {\
return mLibDep1->TestFunction(value); \
}
// the allowed specializations, everything else causes link errors
LI_TESTFUNCTION( int );
LI_TESTFUNCTION( std::string );
Tested this with VC++ 2k8 & g++ 4.3.4 statically linking against LibraryInclude.o