I have a simple class A, providing a variadic function template. This function uses private data from within A, but the function itself is public. The class goes as follows:
class A {
public:
A() :
_bla("bla: ") {
}
template <class T>
void bar(const T& value) {
std::cout << _bla << value << std::endl;
}
template <class H, class... T>
void bar(const H& value, const T&... data) {
std::cout << _bla << value << std::endl;
bar(data...);
}
private:
const std::string _bla;
};
In a separate file, named foo.hpp, I have a function foo(), that should be able to receive and use the function a.bar() as an argument:
int main(int argc, char *argv[]) {
A a;
a.bar(1, "two", 3, 4);
foo(&a.bar);
}
I'm not very sure of where to start, but I've tried the following -- which does not work. How can I do it correctly:
template <typename... T>
inline void foo(void (bar *)(const T&...)) {
unsigned int x(0), y(0), z(0);
bar(x, y, z);
}
Bonus question: is there a way to call not only:
foo(&a.bar);
but also call foo with a.bar bound to some parameters, like:
foo(&(a.bar(p1, p2));
I can simply add p1 and p2 to foo definition itself, like in:
foo(p1, p2, &a.bar);
but it would be semantically better to my purpose if I could add these parameters before.
You cannot pass the address of a function template without instantiating it, because that is treated as a whole overload set (no matter whether the template is variadic or not). You can, however, wrap it in a generic functor:
struct bar_caller
{
template<typename... Ts>
void operator () (A& a, Ts&&... args)
{
a.bar(std::forward<Ts>(args)...);
}
};
And then let your function foo() be defined as follows:
template<typename F>
inline void foo(A& a, F f) {
unsigned int x(0), y(0), z(0);
f(a, x, y, z);
}
So your function call in main() would become:
int main()
{
A a;
a.bar(1, "two", 3, 4);
foo(a, bar_caller());
}
Unfortunately, at the moment there is no way in C++ to easily wrap an overload set in a functor without defining a separate class - as done above for bar_caller.
EDIT:
If you do not want to pass an A object directly to foo(), you can still let your bar_caller encapsulate a reference to the A object on which the function bar() has to be called (just take care of object lifetime, so that you won't be making that reference dangling):
struct bar_caller
{
bar_caller(A& a_) : a(a_) { }
template<typename... Ts>
void operator () (Ts&&... args)
{
a.bar(std::forward<Ts>(args)...);
}
A& a;
};
You could then rewrite foo() and main() as follows:
template<typename F>
inline void foo(F f) {
unsigned int x(0), y(0), z(0);
f(x, y, z);
}
int main()
{
A a;
a.bar(1, "two", 3, 4);
foo(bar_caller(a));
}
Related
I have a bunch of very similar functions:
void foo1(Obj o) {
bar(o.a);
}
void foo2(Obj2 o) {
bar(o.b);
}
void foo3(Obj3 o) {
bar(o.c);
}
How can I reduce the duplicating of code? Can I do something like:
template<typename T, pointerToMember>
void foo(T o) {
bar(o.pointerToMember);
}
And then create all functions like:
foo<Obj, Obj.x>;
...
?
Yes it is possible to have a pointer to member as template parameter:
#include <string>
struct Obj {
int a,b,c;
};
void bar(int x){}
template<typename T, int (T::*pointerToMember)>
void foo(T o) {
bar(o.*pointerToMember);
}
int main() {
Obj x;
foo<Obj,&Obj::a>(x);
}
However, there are different ways that would make the call less verbose. You could pass the member pointer as parameter to be able to deduce it, that would allow to call it as
foo(x,&Obj::a);
Last not least, you could call bar directly
bar(x.a);
Suppose that a class has a member function which should accept either a double(double) function or a class instance with a "MyStructFunc" public member function as an argument:
#include<functional>
#include <type_traits>
struct Caller
{
// (1.)
double call(std::function<double(double)> func) { return func(1); }
// (2.)
template<typename T>
double call(const T& S) { return S.MyStructFunc(2); }
};
So, for example, we can pass
double myFunc(double x) { return x * x * x; }
or
struct myStruct
{
double MyStructFunc(double x) const { return x * x; }
};
like this:
int main()
{
Caller c;
myStruct ms;
c.call(myFunc);
c.call(ms);
}
Unfortunately, I get an error. Could you please help me make it work? Thank you for your help!
function pointer is not a std::function, so your template method is a better match.
You might use SFINAE to restrict your template method:
// (2.)
template<typename T>
auto call(const T& S) -> decltype(S.MyStructFunc(2)) { return S.MyStructFunc(2); }
Demo
I have some structs and an enum that look like this:
enum NUM
{
A = 0,
B,
C
};
struct X{};
struct Y{};
I'd like to create a variadic template for a function that looks like this:
template<NUM n, typename...Args>
void func(const Args&...a);
I'd like to specialize the template function func in cases like this:
if NUM::A define func as
template<> void func<A, X>(const X& x)
{
var.emplace_back(std::make_shared<SomeClass>(x));
}
if NUM::B define func as
template<> void func<B,X,Y>(const X& x, const Y& y)
{
var.emplace_back(std::make_shared<SomeOtherClass>(x,y))
}
Could you help me tidy it up with variadic templates?
Partial specialisation of functions can be achieved by deferring the implementation of the function to a function object template, which because it is a class template, can be partially specialised.
example:
#include <memory>
#include <vector>
enum NUM
{
A = 0,
B,
C
};
struct X{};
struct Y{};
// guess at missing code in question
struct SomeBase
{
virtual ~SomeBase() noexcept;
};
struct SomeClass : SomeBase
{
SomeClass(const X&);
};
struct SomeOtherClass : SomeBase
{
SomeOtherClass(const X&, const Y&);
};
std::vector<std::shared_ptr<SomeBase>> var;
// helper base class
struct func_impl_common
{
func_impl_common(std::vector<std::shared_ptr<SomeBase>>& var) : var(var) {}
std::vector<std::shared_ptr<SomeBase>>& var;
};
// general template
template<NUM n, typename...Args> struct func_impl;
// now specialise for A X
template<> struct func_impl<A, X> : func_impl_common
{
using func_impl_common::func_impl_common;
void operator()(X const& x) const
{
var.push_back(std::make_shared<SomeClass>(x));
}
};
// now specialise for B X Y
template<> struct func_impl<B, X, Y> : func_impl_common
{
using func_impl_common::func_impl_common;
void operator()(X const& x, Y const& y) const
{
var.push_back(std::make_shared<SomeOtherClass>(x, y));
}
};
// define func in terms of function object template
template<NUM n, typename...Args>
void func(const Args&...a)
{
auto op = func_impl<n, Args...>(var);
op(a...);
}
// test
int main()
{
func<A>(X{});
func<B>(X{}, Y{});
}
However, if this is a real design it seems a little suspect.
Basically, what I want to do is to hava a wrapper on some abstract class, then have the same wrapper class wrap around the output of any member function of that class. Keep doing that so that all objects are always wrapped.
Like (presudocode)
wrap<set(1..10)> (multiply,2)
(divide,3)
(plus,5)
(inverse)
(collect first 10)
.unwrap()
All lines above except the last line outputs wrap of something. It seems to be meanling less for now, but I believe then we can apply interesting things on it like:
wrap<someClass> dat;
dat.splitIntoThreads(2)
(thingA) .clone()
(thingB) (thing1)
(thingC) (thing2)
(thingD) (thing3)
.nothing() (thing4)
.sync() .exit()
.addMerge()
Here is my code for wrap:
template<class T>
struct wrap{
wrap(){}
wrap(T b){a=b;}
template<class L,class...R>
L operator() (L(T::*f)(R...),R...r){
return a.f(r...);
}
T a;
};
int main(){
wrap<testClass> a;
a(&testClass::f,13,'a');
}
It's working (gcc, c++0x). But when I replace the 6,7th line with the following (to actually wrap the result)
wrap<L> operator() (L(T::*f)(R...),R...r){
return wrap<L>(a.f(r...));
The compiler just sais: creating pointer to member function of non-class type "int".
How can I fix this? Is there any better to do this? Inheritence is one way but since we might have variable instance in one wrap, I think it's not useful.
EDIT
Here's my test class
struct testClass{
int f(int a,char b){
return a+b;
}
};
The reason why I'm using wrap L instead of wrap T is that the return type might not always be T.
You can try something like this:
#include <iostream>
#include <type_traits>
template<class T, bool = false>
struct wrap{
template <typename... Args>
wrap(Args&&... args) : a{std::forward<Args>(args)...} {};
template<class L, class...R>
wrap<L,std::is_fundamental<L>::value> operator() (L(T::*f)(R...),R...r){
return wrap<L,std::is_fundamental<L>::value > {(a.*f)(r...)};
}
T a;
};
template<class T>
struct wrap <T,true>{
template <typename... Args>
wrap(Args&&... args) : a{std::forward<Args>(args)...} {}
template<class L, class...R>
wrap<L,std::is_fundamental<L>::value> operator() (L(*f)(T a, R...), R...r){
return wrap<L,std::is_fundamental<L>::value > {f(a, r...)};
}
T a;
};
class testClass {
int m;
public:
testClass(int _m) : m{_m}{}
int multiAdd(int x, char y) {
m += x + y;
return m;
}
};
int add(int a, char b)
{
return a+b;
}
int main(){
wrap<testClass> a{0};
std::cout << a(&testClass::multiAdd,0,'d')(add,'a').a<<std::endl;
wrap<int, true> b{3};
std::cout << b(add,'a').a<<std::endl;
}
cpp.sh/6icg
It seems the error is in your testclass definition. Please check the below example.
Also, wrap in the operator() can be returned as reference. I don't see any need to create temporaries to be used for () chaining.
template<class T>
struct wrap{
template <typename... Args>
wrap(Args&&... args) : a{std::forward<Args>(args)...} {};
template<class L, class...R>
wrap<T>& operator() (L(T::*f)(R...),R...r){
a.f(r...);
return *this; //returning reference to current wrap object.
}
T a;
};
A test class to accumulate numbers.
class testClass {
int m;
public:
testClass(int _m) : m{_m}{}
int f(int x) {
m += x;
std::cout << ' ' << m;
return m;
}
};
An usage example:
int main(){
wrap<testClass> a{0};
a(&testClass::f,13)(&testClass::f, 11)(&testClass::f,3)(&testClass::f, 21);
}
Output of sum accumulated at each step:
13 24 27 48
I'm trying to use a template class with a lambda function parameter. However, I don't understand how to pass the parameter. Here's what I've tried so far:
#include <iostream>
using namespace std;
template <class F>
class A {
public:
int f(int i)
{
return F(i); //*
}
};
int main(int argc, const char * argv[]) {
auto f = [](int i){return i+5;};
A<decltype(f)> a;
cout << a.f(5);
return 0;
}
I get an error in the marked line.
Can someone help?
Your example doesn't work because F is a type, not a callable object. The next step is to instantiate it by creating a member variable.
template <class F>
class A {
F function;
public:
int f(int i) {
return function(i);
}
};
However, that still won't work because lambda default constructors are deleted. That means we need another way to construct function. That can be achieved by passing an argument to A's constructor.
template<typename F>
class A {
F function;
public:
A(const F& f) : function(f) {}
int f(int i) {
return function(i);
}
};
// ...
auto f = [](int i) { return i+5; };
A<decltype(f)> a(f);
This uses the lambda copy constructor, which isn't deleted.
Live example
If you want it to work with any lambda, you can add some more magic.
template<typename F>
class A {
F function;
public:
A(const F& f) : function(f) {}
template<typename ...Args>
auto f(Args... args) -> std::result_of_t<F(Args...)> {
return function(std::forward<Args>(args)...);
}
};
Live example
If you really want to use template in order to accept any kind of function's signature, then the implementation should be something similar to this:
class A {
public:
template<typename F, typename... Args>
auto f(F&& funct, Args&&... args) {
return funct(std::forward<Args...>(args)...);
}
};
That because you've said in the comment:
Q: Does the type F is needed in the class of only for method f?
A: only the method.
Because of that, it should be useless to have a template class, when you can just have a template method.
An here, an example how to call the method which just invoke the "callable object with its parameters", in this case a lambda function:
int main(int argc, char* argv[]) {
A a;
a.f([](int i) -> int { return i + 5; }, 12);
// |------callable object-----------| |argument of function|
return 0;
}
Practically, the method f accepts as first argument a "callable object" and as further arguments any parameters requested in order to invoke the first argument.
Additional Notes:
If you want to pass to method f a certain type of signature of function, for example: int (*)(int), then you can avoid using template and pass an object of type std::function.
This is just an example:
#include <functional>
class A {
public:
// method g accept a function which get a integer and return an integer as well.
int g(std::function<int(int)> funct, int arg) {
return funct(arg);
}
};
It's not enough to define A as inherited from or somehow containing a lambda function, you still have to initialize the subobject when you create an instance of A.
To do that, as an example, you can inherit from the lambda and use A as a callable object.
It follows a minimal, working example:
#include <iostream>
using namespace std;
template <class F>
class A: public F {
public:
A(F f): F(f) {}
};
int main() {
auto f = [](int i){return i+5;};
A<decltype(f)> a{f};
cout << a(5);
return 0;
}
You don't have to define any function f to execute the lambda.
Anyway, if you want to have a function f to be called as a.f(5), you can define it as it follows:
int f(int i) {
return F::operator()(i);
}
Or as it follows:
int f(int i) {
return (*this)(i);
}