I have a base class with a vector of pointers, and I think to slide the vector outside this class, I wrote the for_each() method:
class model {
static std::vector<model*> models;
...
public:
template <class C>
static void for_each(C *c,void (C::*f)(model *))
{
for (std::vector<model*>::iterator it=models.begin(); it!=models.end(); ++it) {
c->f(*it);
}
...
}
I tryed to use for_each() in a member function:
void v_context::build_cmd()
{
...
auto f1=[&](model* m)->void{commandBuffers.push_back(*(m->build_secondary_buffers(inheritanceInfo, pipelines.gltf)));};
model::for_each<VulkanExample,void (VulkanExample::*)(model*)>(this,f1);
...
}
The compiler (gcc version 10.2.1 20210110 (Debian 10.2.1-6)), rightly returns the error:
error: cannot convert ‘v_context::build_cmd()::<lambda(model*)>’ to
‘void (v_context::)(model)’
note: initializing argument 2 of ‘static void model::for_each(C*, void
(C::)(model)) [with C=v_context]’
Is it possible? Does correct syntax template exist?
The simplest is probably to make it even more generic:
class model {
static std::vector<model *> models;
public:
template <class Func>
static void for_each(Func&& func) { // no instance needed
for (auto ptr : models) { // simplified loop
func(ptr);
}
}
};
Then just capture [this] in the lambdas you use it with:
void VulkanExample::build_cmd() {
auto f1 = [this](model *m) {
// ...
};
model::for_each(f1);
}
Demo
You could use std::invoke to implement this logic. A class and a member function pointer this would require swapping the parameters, but otherwise this would allow you to pass any number of additional parameters before the model* parameter:
class model
{
...
template <class F, class...Args>
static void for_each(F&& f, Args&&...args)
{
for (auto p : models)
{
std::invoke(f, args..., p);
}
}
...
};
Example usages:
struct Foo
{
void Bar(model*) {}
};
...
Foo foo;
model::for_each(&Foo::Bar, foo);
model::for_each([&](model* m)->void{commandBuffers.push_back(*(m->build_secondary_buffers(inheritanceInfo, pipelines.gltf)));});
Related
Lets say I have a function
template<typename T>
some_function(T a){
// some operations..
}
I have a huge list of classes who objects i want to pass to the function one by one(Don't ask me why I'm forced to have it like that.)
class type1{ //.. whateever is necessary here...
};
class type2{ //.. whateever is necessary here...
};
class type3{ //.. whateever is necessary here...
};
class type4{ //.. whateever is necessary here...
};
.
.
and so on
Is there a way I can instantiate an object of each data and pass it to the function within a loop, rather than type one by one it manually.
(It would be better if the instantiation happens within the loop so that the object is local for every loop).
Any way to approach this problem other than typing it manually is welcome.
EDIT:
Since there were questions in the comments. Let me elaborate on the type of algorithm I am looking for.
Step 1: Pick a class my_class in [type1,type2,...,typeN]
Step 2: Instantiate an object of that class my_class object
Step 3: Pass it to the function some_function(object)
Step 4: Go to step 1 and pick the next class.
I hope I made things clear.
EDIT 2: I use c++11 . But I don't mind switching if it is needed
Let me elaborate on the type of algorithm I am looking for.
Step 1: Pick a class my_class in [type1,type2,...,typeN]
Step 2: Instantiate an object of that class my_class object
Step 3: Pass it to the function some_function(object)
Step 4: Go to step 1 and pick the next class.
If you can use C++11 or newer, and if you can pass immediately the object instantiated to some_function(), you can simulate a loop with a variadic template type list as follows
template <typename ... Ts>
void repeatOverTypes ()
{
using unused=int[];
(void)unused { 0, (some_function(Ts{}), 0)... };
}
The following is a full compiling example
#include <iostream>
class type_1 { };
class type_2 { };
class type_3 { };
class type_4 { };
template <typename T>
void some_function (T a)
{ }
template <typename ... Ts>
void repeatOverTypes ()
{
using unused=int[];
(void)unused { 0, (some_function(Ts{}), 0)... };
}
int main ()
{
repeatOverTypes<type_1, type_2, type_3, type_4>();
}
If you can use C++17, using folding repeatOverTypes() become simply
template <typename ... Ts>
void repeatOverTypes ()
{ (some_function(Ts{}), ...); }
-- EDIT --
The OP say
I overlooked an important detail while trying to simplify the problem. I need to pass the objects by reference. So the Ts{} won't work ? What can i do ?
I see... well, I suppose you can (1) create the Ts{} object and store they in a container (a std::tuple seems to me an obvious container) and (2) pass to some_function() the values extracted from the tuple.
The point (1) is simple
std::tuple<Ts...> t { Ts{}... };
The point (2) heavily depend from the list of type (there are repetitions in "type1,type2,...,typeN" ?) and the exact language.
If all types in the list are different and you can use C++14, you can access the tuple values trough std::get<Ts>(t); so the function can be written
template <typename ... Ts>
void repeatOverTypes ()
{
using unused=int[];
std::tuple<Ts...> t { Ts{}... };
(void)unused { 0, (some_function(std::get<Ts>(t)), 0)... };
}
If there are repetitions, you have to access value via integer index, so you have to create a list of index and pass they to an helper function; something like
template <typename T, std::size_t ... Is>
void rotH (T & t, std::index_sequence<Is...> const &)
{
using unused=int[];
(void)unused { 0, (some_function(std::get<Is>(t)), 0)... };
}
template <typename ... Ts>
void repeatOverTypes ()
{
std::tuple<Ts...> t { Ts{}... };
rotH(t, std::make_index_sequence<sizeof...(Ts)>{});
}
Unfortunately std::index_sequence and std::make_index_sequence are introduced in C++14 so, in C++11, you have to simulate they in some way.
As usual in C++17 is simpler; if you are sure (but really, really sure) that types are all different, the function is simply
template <typename ... Ts>
void repeatOverTypes ()
{
std::tuple<Ts...> t { Ts{}... };
(some_function(std::get<Ts>(t)), ...);
}
In case of types collision, with integer sequence,
template <typename T, std::size_t ... Is>
void rotH (T & t, std::index_sequence<Is...> const &)
{ (some_function(std::get<Is>(t)), ...); }
template <typename ... Ts>
void repeatOverTypes ()
{
std::tuple<Ts...> t { Ts{}... };
rotH(t, std::make_index_sequence<sizeof...(Ts)>{});
}
I have a huge list of classes who objects i want to pass to the function one by one
As you seem to need handling many types and avoid to type them out hardcoded in a single place of your code (as provided in this answer), you should consider using dynamic polymorphism, interfaces and self-registering classes rather.
This is a well known technique when a uniform set of operations needs to be done over a lot of specific class types. Many unit testing frameworks use that in order to avoid that additional test cases need to be added at a central place, but just within the translation unit where they're defined.
Here's a sketch (untested) how to implement such:
Provide an interface to describe what needs to be done in some_function() uniquely:
struct IMyInterface {
virtual ~IMyInterface() {}
virtual void WhatNeedsToBeDone() = 0;
virtual int WhatNeedsToBeKnown() const = 0;
};
void some_function(IMyInterface* intf) {
if(intf->WhatNeedsToBeKnown() == 1) {
intf->WhatNeedsToBeDone();
}
}
Provide a singleton registrar keeping a map of functions to create your classes:
class MyRegistrar {
MyRegistrar() {};
using FactoryFunction = std::function<std::unique_ptr<IMyInterface> ()>;
std::map<std::string, FactoryFunction> classFactories;
public:
static MyRegistrar& ClassRegistry() {
static MyRegistrar theRegistrar;
return theRegistrar;
};
template<typename T>
void registerClassFactory(
FactoryFunction factory) {
classFactories[typeid(T).name()] = factory;
};
template<typename T>
std::unique_ptr<IMyInterface> createInstance() {
return classFactories[typeid(T).name()]();
}
template<typename T>
const FactoryFunction& factory() const {
return classFactories[typeid(T).name()];
}
std::vector<FactoryFunction> factories() const {
std::vector<FactoryFunction> result;
for(auto& factory : classFactories) {
result.push_back(factory);
}
return result;
}
};
also provide a registration helper to make it easier registering the types with the global registrar
template<typename T>
struct RegistrationHelper {
RegistrationHelper(
std::function<std::unique_ptr<IMyInterface> ()> factoryFunc =
[](){ return std::make_unique<T>(); }) {
MyRegistrar::ClassRegistry().registerClassFactory<T>(factoryFunc);
}
};
In your specific types you can use that like
class type1 : public IMyInterface {
static RegistrationHelper<type1> reghelper;
public:
void WhatNeedsToBeDone() override {}
int WhatNeedsToBeKnown() const override { return 0; };
};
RegistrationHelper<type1> type1::reghelper;
You can also specialize to deviate from the default factory function:
enum Color { Red, Green };
class type1 : public IMyInterface {
static RegistrationHelper<type1> reghelper;
Color color_;
public:
type1(Color color) : color_(color) {}
void WhatNeedsToBeDone() override {}
int WhatNeedsToBeKnown() const override { return 0; };
};
RegistrationHelper<type1> type1::reghelper(
[](){ return std::make_unique<type1>(condition? Green : Red);
} -> std::function<std::unique_ptr<IMyInterface> ()>
);
To realize your iteration over all classes you can use
for(auto factory : MyRegistrar::ClassRegistry().factories()) {
std::unique_ptr<IMyInterface> intf = factory();
some_function(intf.get());
}
I'd like to have a collection of lambdas, with the requirement that the lambas must not be copied, only moved.
This is because the lambas may need to move-capture some of their arguments that are not copy-constructible.
Example:
NonCopyableType varName ;
auto func = [a=move(varName)](){ ... } ; //varName is move-captured
After this I want to store func in a vector, but I can't use the std::function type because it requires the lambdas to be copyable.
vector<function<void()>> list ;
list.push_back(func) ; //won't work
Is it possible to do this some other way?
Sure. Just write your own function clone that is move-only. Here's a simplified version that only supports nullary callables, but you can see how it can be extended:
class move_function
{
struct placeholder {
virtual ~placeholder() = default;
virtual void call() = 0;
};
template <class T>
struct holder : placeholder {
T f;
void call() override { f(); }
};
std::unique_ptr<placeholder> f_;
public:
template <class F,
class R = std::result_of_t<F&()>,
std::enable_if_t<!std::convertible<std::decay_t<F>*, move_function*>::value, int> = 0>
move_function(F&& f)
: f_(new std::decay_t<F>{std::forward<F>(f)})
{ }
void operator()() const { f_->call(); }
};
All the implicitly defined special member functions already do the right thing for us.
When compiling the following code:
#include <functional>
template <typename functionSignature>
class Class
{
std::function<functionSignature> func;
public:
Class(const std::function<functionSignature>& arg) : func(arg) {}
void callFunc() { func(); }
};
void f(const int i) {}
int main()
{
Class<void(const int)> a(std::bind(f, 10));
a.callFunc();
return 0;
}
The VS 2015 compiler generates the following error message at the sixth line:
error C2064: term does not evaluate to a function taking 0 arguments.
Now, I believe this is because the compiler thinks functionSignature is not, well, a function signature; the same error happens when I instantiate and try to call operator() on an std::function<int> instead of std::function<int()>, for instance.
How can I guarantee that the template argument will always be a function signature, so that I can call operator() on the std::function?
I suspect you want something like that:
template <typename F>
class Class;
template<typename R, typename... P>
class Class<R(P...)> {
public:
std::function<R(P...)> func;
void callFunc(P... p) { func(p...); }
};
By using partial specialization that way you can easily define the type you want.
As an example, you can use it as:
Class<int(double)> c;
Of course, I noticed that you have no constructors for your class, so to invoke func is not a good idea, but it's quite easy to define it and pass a proper function as an argument.
It follows a complete and working example where I've used the operator() to invoke the function:
#include <functional>
template <typename F>
class Class;
template<typename R, typename... P>
class Class<R(P...)> {
public:
Class(std::function<R(P...)> f): func{f} { }
void operator()(P... p) { func(p...); }
private:
std::function<R(P...)> func;
};
void fn() { }
int main() {
std::function<void()> f = fn;
Class<void()> c{f};
c();
}
Your error is here:
Class<void(const int)> a(std::bind(f, 10));
The function Class::callFunc() invokes func() -- i.e., no arguments. The result of std::bind(f, 10) is also a function that takes no arguments, which is consistent with the template argument to the class template. Using Class<void(const int)> is inconsistent with both the usage in the class template and the initialization.
The solution is easy: Change the errant line to
Class<void()> a(std::bind(f, 10));
Is this what you are trying to do?
http://ideone.com/fork/IZ0Z1A
If functionSignature is NOT a function, std::function will throw errors when you create Class but you could add a constructor and throw there a static_assert(std::is_function<functionSignature>::value == true," ");if you want I guess.
#include <functional>
#include <iostream>
template <typename functionSignature>
class Class
{
public:
std::function<functionSignature> func;
void callFunc() { func(); }
};
void f()
{
std::cout << "hello" << std::endl;
}
int main()
{
Class<decltype(f)> t {f};
t.callFunc();
return 0;
}
When I want to have member function as template argument, is there a way to templetize it without providing Caller type?
struct Foo
{
template <typename Caller, void (Caller::*Func)(int)>
void call(Caller * c) { (c->*Func)(6); }
};
struct Bar
{
void start()
{
Foo f;
f.call<Bar, &Bar::printNumber>(this);
^^^^
}
void printNumber(int i) { std::cout << i; }
};
int main ()
{
Bar b;
b.start();
return 0;
}
when I try
template <void (Caller::*Func)(int), typename Caller>
void call(Caller * c) { (c->*Func)(6); }
and call it like
f.call<&Bar::printNumber>(this);
I am getting Caller is not class... error.
So, is there a way to let compiler deduce the Caller type?
No, not as you want it. Caller could be deduced if
the pointer to member function were an parameter, not a template parameter. Eg:
template <class Caller>
void call(Caller * c, void (Caller::*Func)(int)) { (c->*Func)(6); }
it was known beforehand. For example, you could make the call look like this:
f.arg(this).call<&Bar::printNumber>();
The call function would look similar to this:
template <class Arg>
struct Binder
{
template<void (Arg::*Func)(int)>
void operator()() const {
...
}
};
The arg function would be easy to write (in your case it would return Binder<Bar>, where Bar is deduced from this).
Not very convenient, IMHO.
FastDelegate refers to http://www.codeproject.com/KB/cpp/FastDelegate.aspx, but I don't think it is related.
I have code like following, and got error.
#include <FastDelegate.h>
using namespace fastdelegate;
template <typename T>
T Getter() {}
template <typename T>
void Setter(T) {}
template <typename T>
class Prop
{
public:
typedef FastDelegate0<T> Getter;
typedef FastDelegate1<T> Setter;
Prop(Getter getter, Setter setter) :
m_Getter(getter), m_Setter(setter)
{
}
private:
Getter m_Getter;
Setter m_Setter;
};
template <typename T>
inline Prop<T>* MakeProp(FastDelegate0<T> getter, FastDelegate1<T> setter)
{
return new Prop<T>(getter, setter);
}
static int Target = 0;
int main()
{
FastDelegate0<int> fdGetter(Getter<int>);
Prop<int>* c = MakeProp(fdGetter, Setter<int>);
// ^^^^ error: no matching function for call to 'MakeProp'
}
If changed the main() to:
int main()
{
FastDelegate0<int> fdGetter(Getter<int>);
FastDelegate1<int> fdSetter(Setter<int>);
Prop<int>* c = MakeProp(fdGetter, fdSetter); // It works.
}
or:
int main()
{
FastDelegate0<int> fdGetter(Getter<int>);
Prop<int>* c = MakeProp<int>(fdGetter, Setter<int>); // It works, too.
}
I think, MakeProp() should get the T from fdGetter (which is int, than called the contructor of FastDelegate1<int> automatically. But it did not. Why?
P.S. I would like to save the getter and setter in Prop, any suggestion for this approach is welcome. Maybe it is bad to copy the instance of FastDelegate* during passing arguments in function.
Have you tried
Prop<int>* c = MakeProp(FastDelegate0<int>(Getter<int>), FastDelegate1<int>(Setter<int>));
?
Setter<int> cannot be converted to FastDelegate1<T>!