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.
Related
#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);
}
I have a toy example that I'd like to modify architecturally to remove type dependency of Processor on EmitterT:
#include <iostream>
#include <utility>
using namespace std;
struct Emitter {
void e(int) { cout << "emitting int\n";}
void e(double) { cout << "emitting double\n";}
void e(char*) { cout << "emitting char*\n";}
void e(const char*) { cout << "emitting const char*\n";}
};
template <typename EmitterT>
struct Processor {
Processor(EmitterT e) : e_{e} {}
template <typename T>
void process(T&& value) {
cout << "some processing... ";
e_(std::forward<T>(value));
}
EmitterT e_;
};
template<typename Emitter_>
Processor<Emitter_> makeProcessor(Emitter_ e) { return Processor<Emitter_>(e);}
int main() {
Emitter em;
auto p = makeProcessor([&em](auto v){em.e(v);});
p.process(1);
p.process("lol");
return 0;
}
Motivation
I'd like to decouple part responsible for utilizing results of processing from the processing itself. The Emitter class structure is given to me, so I have to support overloaded functions.
I'd like to pass a lambda function to a processor that will use it. Kind of like a callback mechanism, however it must be a generic lambda, to support overloads.
What I've tried:
The example I wrote works, but it depends on Emitter type as a template parameter. I don't like Processor type to change based on Emitter. It's also contagious, I have a real Processor hierarchy and Emitter spread like const or worse.
After reading https://stackoverflow.com/a/17233649/1133179 I've tried playing with below struct as a member:
struct EmitterC {
template<typename T>
void operator()(T value) { }
};
But I cannot figure out a way to defer implementation of Emitter after Processor when using it as a normal parameter. It worked out with a forward declaration and a reference EmitterC& but it supports one only Emitter definition. The only way I could come up with was to drop lambda, and make virtual overloads in EmitterC for every type I expect in Emitter and use it as a base class.
So, Is there a way to pass the (generic) lambda as a parameter, so that Processor type doesn't depend on Emitter?
I am restricted to c++14, but I am interested in more modern standards as well if the have better support.
This simplest solution is to make Emitter a parameter to process:
struct Processor {
template <typename T, typename EmitterFn>
void process(T&& value, EmitterFn emit) {
cout << "some processing... ";
emit(std::forward<T>(value));
}
};
However, if it must be a member of Processor and you can enumerate the possible function signatures, you can use some kind of type erasure. std::function or the proposed std::function_ref won't work because they only allow a single function signature, but we can write our own overloaded_function_ref:
template <typename Derived, typename Sig>
class function_ref_impl;
template <typename Derived, typename R, typename... Args>
class function_ref_impl<Derived, R(Args...)> {
using fn_t = R(*)(void const*, Args...);
public:
auto operator()(Args... args) const -> R {
return fn(static_cast<Derived const&>(*this).object, std::forward<Args>(args)...);
}
protected:
template <typename F,
std::enable_if_t<!std::is_base_of<function_ref_impl, F>::value, int> = 0>
explicit function_ref_impl(F const& f)
: fn{[](void const* self, Args... args) -> R {
return (*static_cast<F const*>(self))(std::forward<Args>(args)...);
}}
{}
private:
fn_t fn;
};
template <typename... Sig>
class overloaded_function_ref
: public function_ref_impl<overloaded_function_ref<Sig...>, Sig>...
{
public:
template <typename F,
std::enable_if_t<!std::is_base_of<overloaded_function_ref, F>::value, int> = 0>
overloaded_function_ref(F const& f)
: function_ref_impl<overloaded_function_ref, Sig>(f)...
, object{std::addressof(f)}
{}
// Can be done pre-C++17, but it's not easy:
using function_ref_impl<overloaded_function_ref, Sig>::operator()...;
// This can be encapsulated with techniques such as the "passkey" idiom.
// Variadic friend expansion isn't a thing (`friend bases...`).
void const* object;
};
Live example
This does require C++17 for the using
/* base */::operator()..., but that can be emulated in C++14; see the paper that introduced this feature: [P0195], or perhaps Boost HOF's match can be massaged to do this. This is also just a function reference and not an owning function.
Then we can write:
struct Processor {
template <typename T>
void process(T&& value) {
cout << "some processing... ";
emit(std::forward<T>(value));
}
using emitter_t = overloaded_function_ref<
void(int),
void(double),
void(char*),
void(char const*)
>;
emitter_t emit;
};
Demo
IMHO: Inheritance is here for that.
#include <iostream>
#include <utility>
using namespace std;
struct BaseEmitter {
virtual void e(int) =0;
virtual void e(double)=0;
virtual void e(char*)=0;
virtual void e(const char*)=0;
};
struct Emitter :public BaseEmitter {
virtual void e(int) { cout << "emitting int\n";}
virtual void e(double) { cout << "emitting double\n";}
virtual void e(char*) { cout << "emitting char*\n";}
virtual void e(const char*) { cout << "emitting const char*\n";}
};
struct Processor {
BaseEmitter& e_;
Processor(BaseEmitter& e) : e_(e) {}
template <typename T>
void process(T&& value) {
cout << "some processing... ";
e_(std::forward<T>(value));
}
};
int main() {
Emitter em;
auto p = Processor(em);
p.process(1);
p.process("lol");
return 0;
}
You can do a mix in order to capture the lambda, just by inheritance in the interface:
struct bypass
{
virtual void operator()() = 0;
};
template<typename callable> struct capture: public bypass
{
callable& _ref;
capture(callable &ref)
: _ref(ref)
{;};
virtual void operator()()
{
_ref();
}
};
struct test
{
bypass *_c;
template<class T> test(T& callback)
: _c(nullptr)
{
_c = new capture<decltype(callback)>(callback);
};
virtual ~test()
{
delete _c;
};
void doit()
{
(*_c)();
}
};
int main(int argc, char* argv[])
{
auto lambda = [](){std::cout << "hello\n";};
test z=test(lambda);
z.doit();
return 0;
}
If you are willing to pay a high runtime cost in exchange for minimal constraints, you can use std::function with std::any (for C++14, use boost::any):
#include <iostream>
#include <utility>
#include <any>
#include <functional>
struct Processor {
Processor(std::function<void(std::any)> e) : e_{e} {}
template <typename T>
void process(T&& value) {
std::cout << "some processing... ";
e_(std::forward<T>(value));
}
std::function<void(std::any)> e_;
};
struct Emitter {
void e(int) { std::cout << "emitting int\n";}
void e(double) { std::cout << "emitting double\n";}
void e(char*) { std::cout << "emitting char*\n";}
void e(const char*) { std::cout << "emitting const char*\n";}
};
int main() {
Emitter em;
auto p = Processor(
[&em](std::any any){
// This if-else chain isn't that cheap, but it's about the best
// we can do. Alternatives include:
// - Hashmap from `std::type_index` (possibly using a perfect hash)
// to a function pointer that implements this.
// - Custom `any` implementation which allows "visitation":
//
// any.visit<int, double, char*, char const*>([&em] (auto it) {
// em.e(it);
// });
if (auto* i = std::any_cast<int>(&any)) {
em.e(*i);
} else if (auto* d = std::any_cast<double>(&any)) {
em.e(*d);
} else if (auto* cstr = std::any_cast<char*>(&any)) {
em.e(*cstr);
} else {
em.e(std::any_cast<char const*>(any));
}
}
);
p.process(1);
p.process("lol");
return 0;
}
std::any and std::function are both owning type erased wrappers. You may have heap allocations for this, or you might fit inside their small object optimization. You will have virtual function calls (or equivalent).
Compiler Explorer link
Is it possible to pass generic lambda as non-template argument
It is not possible to declare a non-template function that accepts a lambda as an argument. The type of a lambda is anonymous: It has no name. It is not possible to write a function declaration that accepts an argument of an anonymous type.
The type of the lambda can be deduced, which is why lambdas can be passed into function templates whose argument types are deduced.
While this answers the question, it does not offer a solution. I don't think a solution is going to be simple.
I am writing a class member function that will take a lambda with a given type T in the function argument. My question is: is it possible to overload the member function at compile-time based on the mutability of the argument? Below is the example:
// T is a given type for class.
template <typename T>
class Wrapper {
T _t;
// For T&
template <typename F, typename R = std::result_of_t<F(T&)>>
std::enable_if_t<std::is_same<R, void>::value> operator()(F&& f) {
f(_t);
}
// For const T&
template <typename F, typename R = std::result_of_t<F(const T&)>>
std::enable_if_t<std::is_same<R, void>::value> operator()(F&& f) const {
f(_t);
}
};
So, what I want is, if the give lambda is with the following signature, the first operator should be invoked.
[](T&) {
...
};
For constant argument, the second should be invoked.
[](const T&) {
}
If you plan to use non-capturing lambdas only, you can rely on the fact that they decay to pointers to functions.
It follows a minimal, working example:
#include<type_traits>
#include<iostream>
template <typename T>
class Wrapper {
T _t;
public:
auto operator()(void(*f)(T &)) {
std::cout << "T &" << std::endl;
return f(_t);
}
auto operator()(void(*f)(const T &)) const {
std::cout << "const T &" << std::endl;
return f(_t);
}
};
int main() {
Wrapper<int> w;
w([](int &){});
w([](const int &){});
}
Otherwise you can use two overloaded functions as it follows:
#include<type_traits>
#include<iostream>
#include<utility>
template <typename T>
class Wrapper {
T _t;
template<typename F>
auto operator()(int, F &&f)
-> decltype(std::forward<F>(f)(const_cast<const T &>(_t))) const {
std::cout << "const T &" << std::endl;
return std::forward<F>(f)(_t);
}
template<typename F>
auto operator()(char, F &&f) {
std::cout << "T &" << std::endl;
return std::forward<F>(f)(_t);
}
public:
template<typename F>
auto operator()(F &&f) {
return (*this)(0, std::forward<F>(f));
}
};
int main() {
Wrapper<int> w;
w([](int &){});
w([](const int &){});
}
The following example works with passing a member function pointer with no arguments. Can someone explain me how to do this with arguments? If it is possible can we also pass variable number of arguments?
class test {
public:
typedef void (test::*check_fun_type)();
//typedef void (test::*check_fun_type)(int);
void mF1(check_fun_type ptr);
void check1();
void check2(int v1);
};
void test::check1() {
std::cout << "check1" << std::endl;
}
void test::check2(int v1) {
std::cout << "check2 " << v1 << std::endl;
}
void test::mF1(check_fun_type ptr) {
(this->*ptr)();
}
int main() {
test t1;
t1.check1();
t1.check2(2);
t1.mF1(&test::check1);
//t1.mF1((&test::check2)(2));
}
No, you can only pass the arguments when calling it. Such as:
void test::mF1(check_fun_type ptr) {
(this->*ptr)(2);
}
EDIT
You can use std::bind to invoke function with some of its parameters bound to arguments in advance, such as:
test t1;
auto f = std::bind(&test::check2, &t1, 2);
f();
For your case, you need to change the parameter type of test::mF1 to std::function. Such as:
typedef std::function<void(test*)> check_fun_type;
and
void test::mF1(check_fun_type ptr) {
ptr(this);
}
int main() {
test t1;
t1.mF1(std::bind(&test::check2, _1, 2));
}
DEMO
In C++11 you could use
template <class F, class... Args>
void mFx(F ptr, Args... args)
{
(this->*ptr)(args...);
}
to pass member function pointer of any type and variable number of arguments.
In C++98 similar functionality can be achieved by overloading methods for each number of arguments
template <class F>
void mFx(F ptr)
{
(this->*ptr)();
}
template <class F, class A1>
void mFx(F ptr, A1 a1)
{
(this->*ptr)(a1);
}
template <class F, class A1, class A2>
void mFx(F ptr, A1 a1, A2 a2)
{
(this->*ptr)(a1, a2);
}
How do I make the method name (here some_method) a template parameter?
template<typename T>
void sv_set_helper(T& d, bpn::array const& v) {
to_sv(v, d.some_method());
}
There is no such thing as a 'template identifier parameter', so you can't pass names as parameters. You could however take a member function pointer as argument:
template<typename T, void (T::*SomeMethod)()>
void sv_set_helper(T& d, bpn::array const& v) {
to_sv(v, ( d.*SomeMethod )());
}
that's assuming the function has a void return type. And you will call it like this:
sv_set_helper< SomeT, &SomeT::some_method >( someT, v );
Here is a simple example...
#include <iostream>
template<typename T, typename FType>
void bar(T& d, FType f) {
(d.*f)(); // call member function
}
struct foible
{
void say()
{
std::cout << "foible::say" << std::endl;
}
};
int main(void)
{
foible f;
bar(f, &foible::say); // types will be deduced automagically...
}