#include <iostream>
class A
{
public:
A(bool b, int i)
: b_(b) , i_(i) {}
void print()
{
std::cout << b_ << " " << i_ << "\n";
}
private:
bool b_;
int i_;
};
class B
{
public:
B(double d)
: d_(d) {}
void print()
{
std::cout << d_ << "\n";
}
private:
double d_;
};
template<class T=A, typename ... Args>
void f(int a, Args ... args)
{
std::cout << a << std::endl;
T t(args...);
t.print();
}
int main()
{
f(1,false,3);
f<A>(2,true,1);
f<B>(3,2.0);
}
The code above compiles and runs fine. But:
// (class A and B declared as above)
template<class T, typename ... Args>
class F
{
public:
F(int a, Args ... args)
{
std::cout << a << std::endl;
T t(args...);
t.print();
}
};
int main()
{
F<A>(4,true,1);
F<B>(5,2.0);
}
fails to compile with message :
main.cpp: In function ‘int main()’: main.cpp:64:18: error: no matching
function for call to ‘F::F(int, bool, int)’
F(4,true,1);
With your current code, your instantiation of F<A> makes the Args template argument empty, which means the constructor only have the a argument, not args.
It seems that you want only the constructor to have a template parameter pack, not the whole class:
template<class T>
class F
{
public:
template<typename ... Args>
F(int a, Args ... args)
{
std::cout << a << std::endl;
T t(args...);
t.print();
}
};
You made the class a template, not the constructor.
But only the constructor "knows" what the template arguments should be, because those are deduced from the constructor arguments.
That doesn't work.
Instead, you can make the constructor a template, not the class.
Depending of your needs, it should be:
template<class T, typename ... Args>
class F
{
public:
F(int a, Args ... args)
{
std::cout << a << std::endl;
T t(args...);
t.print();
}
};
int main()
{
F<A, bool, int>(4,true,1);
F<B, double>(5,2.0);
}
or
template<class T>
class F
{
public:
template <typename ... Args>
F(int a, Args ... args)
{
std::cout << a << std::endl;
T t(args...);
t.print();
}
};
int main()
{
F<A>(4,true,1);
F<B>(5,2.0);
}
Related
i search on google how to store and to execute functions (template function or not) passing in queue but i didn't find an enough good answer...
this is my code
Window.h
struct QueueEventFunction {
std::vector<std::function<void()>> v; // stores the functions and arguments
// as zero argument lambdas
template <typename F,/*template <typename U, typename = std::allocator<U> >*/ typename ...Args>
void Enqueue(F (*f), Args... args)
{
v.push_back([=] { f(args...); }); // add function and arguments
// as zero argument lambdas
// that capture the function and arguments
}
void CallAll()
{
for (auto f : v)
f(); // calls all the functions
}
};
class Window : public sf::RenderWindow {
public:
Window(sf::VideoMode window, const std::string& title, sf::Uint32 style = 7U, sf::ContextSettings settings = sf::ContextSettings());
~Window();
template <typename F, /*template <typename ...U > */typename ...Args>
void addQueue(F (*f), Args...args);
void execQueue();
private:
QueueEventFunction queue;
}
template <typename F, /*template <typename ...U >*/ typename ...Args>
void Window::addQueue(F (*f), Args...args) {
queue.Enqueue(f, std::forward<Args>(args)...);
}
void Window::execQueue() {
queue.CallAll();
}
TestWindow.cpp
template<typename T>
void add(T a, T b) {
return a + b;
}
class foo{
public:
template<typename T> T add( T a, T b){ return a+ b;}
};
int main() {
Window window(sf::VideoMode(600, 600), "Test Window",7U,sf::ContextSettings());
window.addQueue(add<int>,1,2); // doesn't work
foo bar;
window.addQueue(&foo::add<int>,1,2); // doesn"t work
window.addQueue(bar.add<int>(1,2)); // doesn"t work
return 0;
}
i got a external symbol error.
and if i put a function member class it simply doesn't work. (compilation error)
have you got an idea to correctly make the function addQueue<> with args ?
The big problem with your code is that you take the function pointer as a pointer
template <typename F, typename ...Args>
void Enqueue(F (*f), Args... args)
and
template <typename F, typename ...Args>
void addQueue(F (*f), Args...args);
What you really want is
template <typename F, typename ...Args>
void Enqueue(F f, Args... args)
and
template <typename F, typename ...Args>
void addQueue(F f, Args...args);
And then you can pass any callable thing. Then you can use it with results of bind, lambdas, class member functions, class static member functions, and normal functions.
Then you can use it like
template<typename T>
int add(T a, T b) {
std::cout << "add(" << a << "," << b << ") -> " << a+b << "\n";
return a + b;
}
class foo{
public:
template<typename T>
T add( T a, T b) {
std::cout << "foo::add(" << a << "," << b << ") -> " << a+b << "\n";
return a + b;
}
template<typename T>
static T static_add( T a, T b) {
std::cout << "foo::static_add(" << a << "," << b << ") -> " << a+b << "\n";
return a + b;
}
};
int main() {
Window window(sf::VideoMode(600, 600),"Test Window",7U,sf::ContextSettings());
foo bar;
auto bar_add = [&bar](auto a,auto b){ return bar.add<int>(a,b); };
auto bind_add = std::bind(&foo::add<int>, &bar, std::placeholders::_1, std::placeholders::_2);
window.addQueue(bind_add,5,2);
window.addQueue(bar_add,5,2);
window.addQueue(add<int>,5,2);
window.addQueue(foo::static_add<int>,5,2);
window.execQueue();
return 0;
}
Try it here https://www.onlinegdb.com/t9WczrL-c
I'm trying to implement a wrapper class for a function so that I can add methods to functions. I've created the class, but the operator() only works for some functions. What am I missing?
Code:
#include <iostream>
#include <functional>
template <typename R, typename... Args> class Function;
template <typename R, typename... Args>
class Function<R(Args...)> {
typedef R return_t;
typedef R func_t(Args...);
public:
std::function<func_t> value;
Function(func_t f){
this->value = f;
};
return_t operator()(Args... args){
(std::cout << ... << args) << "\n";
return this->value((..., args));
};
};
typedef int func(int, char);
int f(int, char);
int main(){
func f;
Function<func> t(f);
//std::cout << t.value(10, 'c') << std::endl;
std::cout << t(10, 'c');
}
// Test function
int f(int a, char c){
std::cout << c << std::endl;
return a;
}
I want to save and pass list of template arguments to function.
Like std::thread passes arguments to a thread. Types of arguments are templated and arguments count is not static.
Example, how it will work:
class CallbackList {
public:
Callback(/* Type of list of template args */ args) {
this->saved_args = args;
}
void Call() {
this->callback(saved_args);
}
private:
/* Type of list of template args */ saved_args;
CallbackType callback;
}
Or how can I implement that:
template<typename ...Args>
class CallbackList {
public:
using CallbackPrototype = /* some prototype */;
void RegisterCallback(CallbackPrototype callback, Args... args) {
CallbackInfo callback_info;
callback_info.callback = callback;
callback_info.args = { args... };
this->callbacks.push_back(callback_info);
}
void Call() {
for (CallbackInfo& callback_info : this->callbacks)
callback_info.callback(callback_info.args);
}
private:
struct CallbackInfo {
CallbackPrototype callback;
/* what type should be here? tuple? args count are not static */ args;
};
std::vector<CallbackInfo> callbacks;
}
It is possible?
How can I implement it?
If you do not want your callback to depend on the types of the arguments you have to use some kind of type erasure. You can, for example, use std::function from <functional>:
#include <functional>
#include <iostream>
class Lazy_Callback
{
public:
template <typename F, typename ...Args>
Lazy_Callback(F && f, Args && ...args)
: _fun([=]() { return f(args...); })
{ }
void call() const
{
_fun();
}
protected:
private:
std::function<void()> _fun;
};
void print_int(int x)
{
std::cout << "x = " << x << "\n";
}
int main()
{
Lazy_Callback lc(print_int, 5);
lc.call();
}
If the callback can be templated then you can use std::tuple to store your arguments:
#include <tuple>
#include <iostream>
template <typename F, typename ...Args>
class Lazy_Callback
{
public:
template <typename ...Ts>
Lazy_Callback(F f, Ts && ...ts)
: _f(f), _args(ts...)
{ }
void call() const
{
return std::apply(_f, _args);
}
protected:
private:
F _f;
std::tuple<Args...> _args;
};
template <typename F, typename ...Ts>
Lazy_Callback<F, std::decay_t<Ts>...> make_callback(F && f, Ts && ...ts)
{
return { std::forward<F>(f), std::forward<Ts>(ts)... };
}
void print_int(int x)
{
std::cout << "x = " << x << "\n";
}
int main()
{
auto lc = make_callback(print_int, 5);
lc.call();
}
Are you looking for something like std::bind? Here is a simple example that you could probably expand on:
#include <iostream>
#include <functional>
template <typename T1, typename T2>
void printSum(const T1& a, const T2& b)
{
std::cout << a + b << std::endl;
}
int main()
{
const auto callback = std::bind(&printSum<int, int>, 1, 2);
// ...
callback();
}
How to pass a const member function as a non-const member function to the template?
class TestA
{
public:
void A() {
}
void B() const {
}
};
template<typename T, typename R, typename... Args>
void regFunc(R(T::*func)(Args...))
{}
void test()
{
regFunc(&TestA::A); // OK
regFunc(&TestA::B); // ambiguous
}
Don't want to add something like:
void regFunc(R(T::*func)(Args...) const)
Is there a better way?
Why not simply pass it to a generic template function:
see live
#include <iostream>
#include <utility>
class TestA
{
public:
void A() { std::cout << "non-cost\n"; }
void B() const { std::cout << "cost with no args\n"; }
void B2(int a) const { std::cout << "cost with one arg\n"; }
const void B3(int a, float f) const { std::cout << "cost with args\n"; }
};
template<class Class, typename fType, typename... Args>
void regFunc(fType member_fun, Args&&... args)
{
Class Obj{};
(Obj.*member_fun)(std::forward<Args>(args)...);
}
void test()
{
regFunc<TestA>(&TestA::A); // OK
regFunc<TestA>(&TestA::B); // OK
regFunc<TestA>(&TestA::B2, 1); // OK
regFunc<TestA>(&TestA::B3, 1, 2.02f); // OK
}
output:
non-cost
cost with no args
cost with one arg: 1
cost with args: 1 2.02
No, you have to specify the cv and ref qualifiers to match. R(T::*func)(Args...) is a separate type to R(T::*func)(Args...) const for any given R, T, Args....
As a terminology note, it isn't ambiguous. There is exactly one candidate, it doesn't match. Ambiguity requires multiple matching candidates.
How to implement a very simple edition of boost::bind, which does not bind arguments, but offer a way to call member function in c++ classes.
Here is my first try:
#include <iostream>
struct Foo {
void x(int i) { std::cout << "Foo " << i << std::endl; }
};
struct Bar {
void y(int i) { std::cout << "Bar " << i << std::endl; }
};
template<typename A1, typename I, typename M>
struct Binder {
Binder(I i, M m) : i_(i), m_(m) { }
void operator()(A1 a1) {
(i_->*m_)(a1);
}
I i_;
M m_;
};
template<typename A1, typename I, typename M>
Binder<A1, I, M> my_bind(I i, M m) {
return Binder<A1, I, M>(i, m);
}
int main(int argc, const char *argv[])
{
Foo foo;
Bar bar;
Binder<int, Foo*, void (Foo::*)(int)> b1 = my_bind<int>(&foo, &Foo::x);
Binder<int, Bar*, void (Bar::*)(int)> b2 = my_bind<int>(&bar, &Bar::y);
b1(1);
b2(2);
return 0;
}
The implementation above does work, and will print:
Foo 1
Bar 2
The problem is that the two invokes of my_bind returns objects of different types. How can I alter the program, such that my_bind will return a type which only depends on A1.
The problem is that the two invokes of my_bind returns objects of different types. How can I alter the program, such that my_bind will return a type which only depends on A1.
It is possible to do with type erasure.
In short:
Create Abstract class with interface you like to have. It may have some template parameters. (AbstractBinder in below code)
Create Concrete class which implements this interface. Concrete class may have more template arguments than interface. (Binder class below)
Create Holder class with template constructor - which creates Concrete class, but stores only pointer to it's base Abstract class. So, Holder class has only template parameters required for Abstract interface, while its constructor has all the rest template parameters required for Concrete class. (BinderHolder class below)
live demo
Usage:
int main()
{
Foo foo;
Bar bar;
BinderHolder<int> b1 = my_bind<int>(&foo, &Foo::x);
BinderHolder<int> b2 = my_bind<int>(&bar, &Bar::y);
b1(1);
b2(2);
}
Full code:
template<typename A1>
struct AbstractBinder
{
virtual void call(A1 a1)=0;
virtual AbstractBinder<A1> *clone()=0;
virtual ~AbstractBinder(){}
};
template<typename A1, typename I, typename M>
struct Binder : AbstractBinder<A1>
{
Binder(I i, M m) : i_(i), m_(m) { }
void call(A1 a1)
{
(i_->*m_)(a1);
}
virtual AbstractBinder<A1> *clone()
{
return new Binder(*this);
}
I i_;
M m_;
};
template<typename A1>
class BinderHolder
{
AbstractBinder<A1> *ptr;
BinderHolder &operator=(const BinderHolder&);
public:
template<typename I, typename M>
BinderHolder(I i, M m)
: ptr(new Binder<A1,I,M>(i,m))
{
}
BinderHolder(const BinderHolder &rhs)
: ptr(rhs.ptr->clone())
{
}
~BinderHolder()
{
delete ptr;
}
void operator()(A1 a1)
{
ptr->call(a1);
}
};
template<typename A1, typename I, typename M>
BinderHolder<A1> my_bind(I i, M m) {
return BinderHolder<A1>(i, m);
}
#include <iostream>
struct Foo {
void x(int i) { std::cout << "Foo " << i << std::endl; }
};
struct Bar {
void y(int i) { std::cout << "Bar " << i << std::endl; }
};
int main()
{
Foo foo;
Bar bar;
BinderHolder<int> b1 = my_bind<int>(&foo, &Foo::x);
BinderHolder<int> b2 = my_bind<int>(&bar, &Bar::y);
b1(1);
b2(2);
}
P.S. If you are sure, that all your Concrete classes would have same size, then you can replace heap allocations with placement new inside to fixed size buffer, and add static_assert for safety.