This is a template function that takes a pointer (or a pointer like object) and a member function:
template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
return (ptr->*func)();
}
If works when used with ordinary pointer:
struct C
{
int getId() const { return 1; }
};
C* c = new C;
example(c, &C::getId); // Works fine
But it does not work with smart pointers:
std::shared_ptr<C> c2(new C);
example(c2, &C::getId);
Error message:
error: C2296: '->*' : illegal, left operand has type 'std::shared_ptr<C>'
Why? and How to make something that works with both?
std::shared_ptr doesn't support pointer-to-member access operator (i.e. ->* and .*). So we can't invoke member function pointers with ->* on it directly. You can change the invoking syntax to use operator* and operator.*, which works for both raw pointers and smart pointers.
template <typename Ptr, typename MemberFunctor>
int example(Ptr ptr, MemberFunctor func )
{
return ((*ptr).*func)();
}
LIVE
std::shared_ptr doesn't have an operator->*. You have two main options:
You could write an overload which takes a std::shared_ptr (maybe one for std::unique_ptr as well):
template <typename T, typename MemberFunctor>
int example(std::shared_ptr<T> ptr, MemberFunctor func )
{
return ((ptr.get())->*func)();
}
However, I would suggest just making example take a reference to T and calling func on it. example doesn't need to know anything about how the pointer is stored, so it shouldn't require all of these extra overloads.
template <typename T, typename MemberFunctor>
int example(T&& t, MemberFunctor func )
{
return (std::forward<T>(t).*func)();
}
Now if you have a std::shared_ptr<T>, you'd call example like:
example(*my_shared_ptr, my_func);
std::shared_ptr doesn't overload operator ->*. You may add a overload:
template <typename Ptr, typename MemberFunctor>
int example(std::shared_ptr<Ptr> ptr, MemberFunctor func )
{
return (ptr.get()->*func)();
}
Related
So for this function:
template<typename T>
T popObject(ScriptObject obj) { //Preforms a cast from void* on each to its type.
assert(obj.getType() == std::type_index(typeid(T))); //Ensure type Safety.
return obj.get<T>();
}
template <typename C, typename...Args>
void bind(const char* name, C* context, void(C::* function)(Args...)) {
std::vector<std::type_index> arguments = { std::type_index(typeid(Args))... };
auto functor = [](void* func,void* contex, std::vector<ScriptObject> stack) {
std::size_t idx = 0;
//Call class context -> function (Args...)
};
_functions[name] = new BoundFunction(functor, void_cast(function), context, arguments);
}
I'm unsure of the syntax for calling the member function.
Iv tried:
union MF{
void(C::* pf)(Args...);
void* p;
} mf;
mf.p = func;
contex->*(mf.pf)(popObject<Args>(stack[idx++])...);
Which does not compile, Stating: "Does not evaluate to a function taking 1 Arguments."
Tried std::invoke, But I Don't know how to Specify the Member function Signature for arg1.
So If i have a reference to the member function, And a reference to the instance of the class, As well as the template information to Derive type information. How do I call the Classes member function?
Thanks #Igor Tandentnik
Final Solution was:
(static_cast<C*>(ctx)->*(mf.pf))(popObject<Args>(stack[idx++])...);
As Igor pointed out, it needed to be ->* instead of .*, and added parenthesis, as -> has a lower priority then the Function call operator.
Also, thanks #TheFloatingBrain for pointing out the extra static_cast
Assuming I have a function like the following in C++:
template<typename Container>
void doNothing(Container * container) {
for (auto element: container) {
std::cout << element;
}
}
Would it be possible to "simulate" methods on various classes that could implement this function by passing this to it instead of the first parameter. (E.g. a class like std::vector, std::string ... etc).
So basically instead of having to use it as:
std::vector<double> a{1, 2, 0.5}:
doNothing(a);
I could call it as:
std::vector<double> a{1, 2, 0.5}:
a.doNothing();
No, you can't do that.
The this parameter in the call a.b() is implicit, and there's no way to fake an implicit parameter.
The a.b() syntax is simply not available to you unless b is a member.
You can always simulate a member function by passing the this pointer of an object.
After all, that's all the compiler is doing for proper member functions (passing this as a hidden first parameter).
So, if you want a function foo to behave like a member and operate on an object (ignoring private/protected here) of type Bar, then you could declare it as:
void foo(Bar* self);
and call it like
Bar b;
foo(&b);
(or from inside a Bar member: foo(this);)
then it would be able to access members of b and call its functions by dereferencing the self pointer.
template<class F>
struct poly_mem_ptr_t{
F f;
template<class T>
friend auto operator->*( T* t, poly_mem_ptr_t self )const{
return
[t, f=self.f](auto&&...args)->decltype(auto){
return f(t, decltype(args)(args)...);
};
}
template<class T>
friend auto operator->*( T& t, poly_mem_ptr_t self )const{
return std::addressof(t)->*self;
}
};
template<class F>
poly_mem_ptr_t<F> poly_mem_ptr(F f){ return {std::move(f)}; }
Sample use:
auto do_nothing = poly_mem_ptr([](auto* ptr){ doNothing(ptr); });
std::vector<int> v={1,2,3};
(v->*do_nothing)();
not exactly what you want, but close.
As a benefit, you can add
template<class...Ts>
friend decltype(auto) operator->*( std::variant<Ts...>& var, poly_mem_ptr_t self )const{
return [&var, f=self.f](auto&&...args) {
return std::visit( [&](auto&&t)->decltype(auto){
return f( decltype(t)(t), decltype(args)(args)... );
}, var);
};
}
and now you can take a std::variant and use these poly_mem_ptrs as visitors.
With a bit of work you can also tool up an augmented std::any to support a fixed set of poly_mem_ptrs.
I am looking for a way to convert function object to function pointer.
Captureless lambda has implicit conversion that allows to:
using fptr_t = int (*)(int);
fptr_t ptr = nullptr;
ptr = [](int) { return 2; };
ptr = [](auto) { return 3; };
(*ptr)(42);
I try to do the same with old-fashioned, empty class function objects like:
struct Foo {
int operator()(int) const { return 5; }
} foo;
Or std predicates like std::less<int>.
One way I found is to wrap call of foo with lambda.
If I can assure that foo is stateless and const
I dont really need this ptr and lambda-capture:
template <typename R, typename... Args>
struct to_function_pointer<R(Args...)> {
private:
template <typename T, REQUIRES(std::is_empty<T>::value)>
static T const& stateless_const() {
return (*static_cast<T const*>(nullptr));
}
public:
using pointer = R (*)(Args...);
template <typename U>
pointer operator()(U) const {
return [](Args... args) {
return stateless_const<std::decay_t<U>>()(args...);
};
}
};
But here I do not know how to provide perfect forwarding,
cause [](Args&&...) or [](auto&&...) cannot convert to R(*)(Args...).
Such trick fails when args is noncopyable like std::unique_ptr<int>.
I know that I could use std::function, but it's kind of heavy-weight, while I am trying to get a light-weight solution.
Live example.
Any advice appreciated.
I believe you can simplify your to_function_pointer with just:
template <typename R, typename... Args>
struct to_function_pointer<R(Args...)> {
using pointer = R(*)(Args...);
template <typename U, REQUIRES(std::is_empty<U>::value && std::is_trivially_constructible<U>::value)>
pointer operator()(U ) const
{
return [](Args... args) {
return U{}(std::forward<Args>(args)...);
}
}
};
Few things to note. Args... will already be references or not, you're providing that signature. So forward<> will still do the same thing - the function just happens to not be a template here. Also, scrap the weird nullptr cast. That just looks bad - if we just require trivial constructibility we can just write U{} which seems way cleaner to me.
I want to call a function of a library (that I can not modify)
void function(int* i, char* c);
Is there a way to call the function defining the int and the char on the fly?
i.e. doing something like
function(&1, &'v');
instead of
int int_1 = 1;
char char_1 = 'v';
function(&int_1, &char_v);
This would enormously decrease the length of my code while increasing readability.
As others have noted, the answer is no...
You could simulate it by overloading function :
void function(int i, char c)
{
function(&i, &c);
}
So now you can write function(1, 'v')
Why would you want to do so? Passing a variable as a non const pointer indicates that the callee intends to modify the parameter that is passed therefore it cannot be an rvalue.
So passing a pointer to a literal would be meaningless (unless it is a string literal which is different). Moreover as it is obvious to you, you cannot determine an address of a literal as it is not addressable. The only constant that could be meaningful is a null pointer or some absolute address to an addressable memory
Yes - you can.
function((int*)&(const int &)1, (char*)&(const char &)'v');
And it's completely legal as long as the pointers aren't dereferenced after the function call. This is because they have temporary life-time which equals the full expression in which the function call exists.
They can be used by the function to modify the data without any possible issues.
Life example. Note that the function 'function' isn't defined. The example only demonstrates that such function call is completely valid.
Note: The complexity of this syntax is due to some 'C++' security measures. After all passing a pointer to unnamed data is something you do rare. However this doesn't mean that this structure is illegal or UB.
FISOCPP's answer is nice, but I don't like the way temporary is created.
It can be done this way with compound lateral syntax:
function(&(int){1}, &(char){'v'});
Both ways that uses temporary cause gcc to emit warnings when you try to take the address, although it's perfectly defined valid code.
Interestingly, as compound lateral has automatic storage in C rather temporary storage in C++, so there won't be even warnings if compiled in C99 mode.
You can make this happen in C++11:
#include <type_traits>
#include <iostream>
template <typename Param, typename Arg>
Param take_address_if_necessary_impl (Arg&& arg, std::true_type, std::false_type)
{
return arg;
}
template <typename Param, typename Arg>
Param take_address_if_necessary_impl (Arg&& arg, std::false_type, std::true_type)
{
return &arg;
}
template <typename Param, typename Arg>
Param take_address_if_necessary (Arg&& arg)
{
return take_address_if_necessary_impl <Param> (
arg,
typename std::is_convertible <Arg, Param>::type {},
typename std::is_convertible <typename std::add_pointer <Arg>::type, Param>::type {}
);
}
template <typename Ret, typename... Params, typename... Args>
Ret call_special (Ret (*f) (Params...), Args&&... args)
{
return f (take_address_if_necessary <Params, Args> (args)...);
}
template <typename... Params, typename... Args>
void call_special (void (*f) (Params...), Args&&... args)
{
f (take_address_if_necessary <Params> (args)...);
}
void function (int* i, char* c)
{
std::cout << *i << ' ' << *c << std::endl;
}
int main ()
{
int i = 42;
char c = '%';
call_special (function, 1, 'f');
call_special (function, &i, '?');
call_special (function, &i, &c);
}
The above program yields
1 f
42 ?
42 %
as you'd expect.
There are some caveats here: first, this will fail if you try to use an overloaded function, because C++ can't deduce an overloaded function to a function pointer:
void bar (int);
void bar (float);
call_special (bar, 3.0f); // Compiler error
You might be able to fix this with explicit template arguments:
call_special <float> (bar, 3.0f); // Works
Or of course explicitly typing the function:
call_special ((void (*) (float))bar, 3.0f);
Second, for simplicity's sake, call_special and its helpers play fast and loose with value classes. It may need more work to be able to handle rvalues, const values, etc. robustly.
Third, arguments that can be passed both as values and as pointers will not work. In fact, conversions in general are probably going to cause headaches:
void quux (long* i)
{
if (i)
std::cout << *i << std::endl;
else
std::cout << "(null)" << std::endl;
}
call_special (quux, NULL); // What does this print?
You may be better off using a function to grab the address explicitly:
template <typename T>
T* foo (T&& t)
{
return &t;
}
function (foo (3), foo ('7'));
Note that whatever method you use, you're going to be dealing with temporaries, which die at the semicolon. So if the library you're using stores a reference to an argument you give it, you have no choice but to explicitly give storage to the argument.
Something that can be assigned to or have its address taken is an lvalue.
Something that cannot have its address taken, nor be assigned to (sortof), is an rvalue.
This is a function that takes an rvalue, and converts it to an lvalue. This lvalue will only be valid as long as the source rvalue was valid, which hopefully is long enough:
template<class T>
T& as_lvalue(T&& t){return t;}
template<class T>
void as_lvalue(T&)=delete;
We then use it as follows:
function(&as_lvalue(1), &as_lvalue('v'));
as_lvalue is roughly the opposite operation of std::move, which could otherwise be called as_rvalue. It isn't completely the opposite, because I made lvalue-to-lvalue conversion generate an error.
Now, unary & can be overloaded. So we can write:
template<class T>
T* addressof_temporary(T&& t) {
return std::addressof( as_lvalue(std::forward<T>(t)) );
}
then call:
function(addressof_temporary(1), addressof_temporary('v'));
if paranoid.
I am writing a wrapper class for callable types (pointer to function, functors, etc). I want to implement something like std::function.
I define constructor from pointer to function:
template <typename Ret, typename... Args>
class function<Ret(Args...)>
{
public:
function(Ret (func)(Args...))
{
m_fn_ptr = func;
}
}
Now, let's assume that i want to use my class like this:
int int_function(int n)
{
return n;
}
function<int(short)> wrapper(&int_function); // compile error
Despite that short are implicit convertable to int compiler cannot deduce template parameters and call appropriate constructor.
Then i tried this:
template <typename FRet, typename... FArgs>
function(FRet (func)(FArgs...))
{
m_fn_ptr = static_cast<Ret (*f)(Args...)>(func);
}
But I got invalid static cast.
How can I fix that ?
The super_func is a function object with no state that can convert to any compatible call signature.
template<class T>using type=T;
template<class Sig, Sig* func>
struct super_func;
template<class R, class...Args, R(*func)(Args...)>
struct super_func<R(Args...), func> {
using Sig = R(Args...);
using pSig = Sig*;
template<class R2, class...Args2, std::enable_if_t<
std::is_convertible<
std::result_of_t<pSig(Args2...)>,
R2
>{}
&& !std::is_same<R2, void>{},
bool
> =true>
constexpr operator type<R2(Args2...)>*() const {
return [](Args2...args)->R2{
return func(std::forward<Args2>(args)...);
};
}
template<class...Args2, std::enable_if_t<
std::is_same<
std::result_of_t<pSig(Args2...)>,
R
>{},
bool
> =true>
constexpr operator type<void(Args2...)>*() const {
return [](Args2...args)->void{
func(std::forward<Args2>(args)...);
};
}
constexpr operator pSig() const {
return func;
}
constexpr R operator()(Args...args)const{
return func(std::forward<Args>(args)...);
}
};
live example. A super_func is stateless. To use it on a function foo, do:
super_func< decltype(foo), &foo > super_foo;
and you get a callable stateless empty object which behaves a lot like foo does, except you can assign it to a pointer to any compatible function pointer and it generates it "on the fly" at compile time.
A super_foo can be fed to your function object.
Doing this on the fly doesn't work without the exterior help, as we need the foo to be a truly static bit of information. By the time it becomes a variable, it is too late to do this statelessly, so we cannot use the lambda trick (without an extra pvoid) to generate a function pointer for the exact signature we want.
You could do a macro:
#define SUPER(X) super_func< decltype(X), &X >{}
and then create your function object with function<double()> f(SUPER(foo));
Another approach is to store an extra pointer's worth of state, and create "the fastest possible delegate" style type erasure. (that term can be googled for one of many implementations, each faster than the last).
How can I fix that ?
Use the correct types when creating wrapper.
Instead of using
function<int(short)> wrapper(&int_function);
use
function<int(int)> wrapper(&int_function);
Remember that class templates instantiated with int and short are very different types and are not convertible to each other.
template <typename T> struct Foo {};
Foo<int> a;
Foo<short> b = a; // Not OK.
Foo<short> c;
Foo<int> d = c; // Not OK.
Your function constructor expects a pointer to a function that takes a short, not an int. The fix is to provide it such a function. The easiest way to do that is to use a lambda with an empty capture-list, that is implicitly convertible to a function pointer:
function<int(short)> wrapper( [](short s) { return int_function(s); } );