I have a Register function which takes a std::function<void(const uint8_t* data, size_t len)> as a parameter. I want to use the member function of an object as the target.
I found this question according to which the answer is to use std::bind to bind the first first argument (the implicit this pointer) to the actual object pointer and then use it as the std::function argument.
This however doesn't work anymore in neither C++11, C++14 nor C++17?
Consider the following test program.
#include <iostream>
#include <cstdint>
#include <functional>
void Register(std::function<void(const uint8_t* data, size_t len)> func) {
//Dummy - directly call into function
func(nullptr, 0);
}
class TestClass {
public:
void TestRegister() {
Register(
std::bind(&TestClass::TestTarget, this, std::placeholders::_1)
);
}
void TestTarget(const uint8_t* data, size_t len) {
(void) data;
(void) len;
std::cout << "Hello there" << std::endl;
}
};
int main() {
TestClass testObj;
testObj.TestRegister();
return 0;
}
When compiling for -std=c++17 this throws a rather cryptic error message (I have no idea what it's trying to say here with Wrong number of arguments for pointer-to-member):
In file included from /home/max/Documents/TestingFunctions/main.cpp:3:0:
/usr/include/c++/7/functional: In instantiation of ‘struct std::_Bind_check_arity<void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>’:
/usr/include/c++/7/functional:854:12: required from ‘struct std::_Bind_helper<false, void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>’
/usr/include/c++/7/functional:875:5: required by substitution of ‘template<class _Func, class ... _BoundArgs> typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(const unsigned char*, long unsigned int); _BoundArgs = {TestClass*, const std::_Placeholder<1>&}]’
/home/max/Documents/TestingFunctions/main.cpp:14:78: required from here
/usr/include/c++/7/functional:841:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
/home/max/Documents/TestingFunctions/main.cpp: In member function ‘void TestClass::TestRegister()’:
/home/max/Documents/TestingFunctions/main.cpp:14:26: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = void (TestClass::*)(const unsigned char*, long unsigned int); _BoundArgs = {TestClass*, const std::_Placeholder<1>&}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<void (TestClass::*(TestClass*, std::_Placeholder<1>))(const unsigned char*, long unsigned int)>](((TestClass*)this), std::placeholders::_1)’ from ‘std::_Bind_helper<false, void (TestClass::*)(const unsigned char*, long unsigned int), TestClass*, const std::_Placeholder<1>&>::type {aka std::_Bind<void (TestClass::*(TestClass*, std::_Placeholder<1>))(const unsigned char*, long unsigned int)>}’ to ‘std::function<void(const unsigned char*, long unsigned int)>’
std::bind(&TestClass::TestTarget, this, std::placeholders::_1)
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Replacing the TestRegister function with one that does the exact same thing in a lambda expression compiles and runs without problems.
void TestRegister() {
Register(
[this](const uint8_t* data, size_t len) {
TestTarget(data, len);
}
);
}
Question: Why does the std::bind approach from the linked question not work? Was this feature removed or do I have an error in my code?
Your function Register expects a function with two parameters, but you try to pass to it a function with one placeholded parameter.
void TestRegister() {
Register(
std::bind(&TestClass::TestTarget, this, std::placeholders::_1, std::placeholders::_2)
);
}
Your function takes two parameters, while you are only passing one placeholder.
std::bind(&TestClass::TestTarget, this, std::placeholders::_1, std::placeholders::_2);
Related
I have a class with a constructor but the compilation fails with the error:
error: use of deleted function 'std::atomic<long unsigned int>::atomic(const std::atomic<long unsigned int>&)'
I'm struggling to understand what this error means. I've been trying to update some code from using tbb::atomic to using std::atomic, and this error wasn't appearing before with tbb::atomic.
The bit of code that upsets the compiler is:
#include <boost/aligned_storage.hpp>
template <typename T>
class Holder<T,true>
{
public:
//! Construct a value (there mustn't be one already)
template <typename ARG>
void Construct(const ARG &arg) { new(Raw()) T(arg); }
private:
typename boost::aligned_storage<sizeof(T), boost::alignment_of<T>::value>::type impl;
void *Raw() { return &impl; }
};
Specifically the line:
void Construct(const ARG &arg) { new(Raw()) T(arg); }
I'd be very grateful if anyone could help me understand what is going on.
EDIT:
Full error message:
holder.hpp:75:34: error: use of deleted function 'std::atomic<long unsigned int>::atomic(const std::atomic<long unsigned int>&)'
75 | void Construct(const T &arg) { new(Raw()) T(arg); }
| ^~~~~~~~~~~~~~~~~
In file included from /include/TPtools/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp:19,
from /include/TPtools/boost/smart_ptr/detail/sp_counted_base.hpp:48,
from /include/TPtools/boost/smart_ptr/detail/shared_count.hpp:29,
from /include/TPtools/boost/smart_ptr/shared_ptr.hpp:28,
from /include/TPtools/boost/shared_ptr.hpp:17,
from movegate.cpp:14:
/pkgsData/gcc-v9.3.0p1/Linux/RHEL6.0-2013-x86_64/include/c++/9.3.0/atomic:824:7: note: declared here
824 | atomic(const atomic&) = delete;
| ^~~~~~
holder.hpp: In instantiation of 'void Holder<T, true>::Construct(const T&) [with T = std::atomic<long unsigned int>; T = std::atomic<long unsigned int>]':
element.hpp:185:9: required from 'void Element<PRESENT, ABSENT>::Accessor<PRESENCE>::MakePresentImpl(const ARG&) const [with ARG = std::atomic<long unsigned int>; PRESENCE = Cluster<Element<std::atomic<long unsigned int>, Link>, true>::NonLockingPresence; PRESENT = std::atomic<long unsigned int>; ABSENT = Link]'
element.hpp:119:7: required from 'Element<PRESENT, ABSENT>::PresentResult Element<PRESENT, ABSENT>::Accessor<PRESENCE>::MakePresent(const ARG&) const [with ARG = std::atomic<long unsigned int>; PRESENCE = Cluster<Element<std::atomic<long unsigned int>, Link>, true>::NonLockingPresence; PRESENT = std::atomic<long unsigned int>; ABSENT = Link; Element<PRESENT, ABSENT>::PresentResult = std::atomic<long unsigned int>&]'
dispenser.hpp:78:5: required from 'Index Dispenser<T>::Insert(const T&) [with T = std::atomic<long unsigned int>]'
Most examples don't clearly show how to create a std::function with a static class method that takes an object instance as the first parameter.
I would like to take a static class method that takes an object instance as the first parameter and create a new function that can be used as a C-style callback function and has access to an object instance.
I seem to have tried everything. I took the example here and tried to refactor it to my use case with no luck by using a similar examples here.
See more up-to-date example below
#include <functional>
#include <iostream>
struct Foo
{
Foo(int me) : m_me(me) {}
static int foo_static(Foo* f, int a, int b) { return f->m_me + a + b; }
int m_me;
};
int main()
{
Foo f(4);
using std::placeholders::_1;
std::function<int(int,int)> new_func = std::bind(&Foo::foo_static, &f, _1);
std::cout << new_func(3, 4) << std::endl;
}
EDIT
Forgot compiler output
$ c++ main.cpp -std=c++14
main.cpp:25:30: error: no viable conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to
'std::function<int (int, int)>'
std::function<int(int,int)> new_funct = std::bind(&Foo::foo_static, &f, _1);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1627:5: note: candidate constructor not
viable: no known conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to 'std::nullptr_t'
(aka 'nullptr_t') for 1st argument
function(nullptr_t) _NOEXCEPT : __f_(0) {}
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1628:5: note: candidate constructor not
viable: no known conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to
'const std::__1::function<int (int, int)> &' for 1st argument
function(const function&);
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1629:5: note: candidate constructor not
viable: no known conversion from '__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>' to
'std::__1::function<int (int, int)> &&' for 1st argument
function(function&&) _NOEXCEPT;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/functional:1631:5: note: candidate template
ignored: requirement '__callable<__bind<int (*)(Foo *, int, int), Foo *, const __ph<1> &> >::value' was not satisfied [with _Fp =
std::__1::__bind<int (*)(Foo *, int, int), Foo *, const std::__1::placeholders::__ph<1> &>]
function(_Fp);
^
1 error generated.
Here's a bit more detail on what I'm trying to accomplish. The m_callback is what I'm trying to setup. I could push what I need in the callback into the ClientData but I like the Command structure to hold on to it's data and not have to create a new structure to pass as the ClientData per command.
#include <functional>
#include <iostream>
#include <string>
typedef void (* callback) (Client* client, ClientData* client_data);
struct Command
{
int execute() = 0;
}
struct Search : Command
{
enum SearchType { kType1, kType2 };
Search(Logger log, std::string query, SearchType type) : m_log(log), m_callback(), m_query(query), m_typ(type)
{
m_callback = // create callback
}
int execute(Client* client, ClientData* client_data)
{
client->query(client_data, m_callback, m_query, m_type);
}
static int my_callback(Foo* f, Client* client, ClientData* client_data);
Logger& m_log;
callback m_callback;
std::string m_query;
SearchType m_type;
// other data I want in the callback that isn't passed in client_data
};
int main()
{
Logger log;
Search search(log, "some search", Search::kType1);
Client client;
ClientData client_data;
search.execute(&client, client_data);
}
So I figured out what I was doing wrong with the std::bind but now I need to convert that to the C-style callback I need to work with.
The bind function has something wrong, you have used _1 only however you need to pass 2 arguments.
Change this:
using std::placeholders::_1;
std::function<int(int,int)> new_func = std::bind(&Foo::foo_static, &f, _1);
To
using std::placeholders::_1;
using std::placeholders::_2;
std::function<int(int,int)> new_func = std::bind(&Foo::foo_static, &f, _1,_2);
I was trying to port a CUDA project into ROCm platform which make use of C++ templates extensively. During this process, I am getting following compilation error
/root/warp-ctc/include/detail/gpu_ctc.h:381:5: error: no matching function for call to 'hipLaunchKernelGGL'
hipLaunchKernelGGL((prepare_stable_SM_kernel<ProbT, VT>), dim3(grid_size), dim3(NT), 0, stream_, ctc_helper::identity<ProbT>(), probs_,
^~~~~~~~~~~~~~~~~~
.....
.....
/opt/rocm/hip/include/hip/hcc_detail/functional_grid_launch.hpp:138:13: note: candidate function [with Args = <ctc_helper::identity<float, float>, float *,
float *, int, int>, F = void (*)(ctc_helper::identity<float, float>, float *, float *, int, int)] not viable: no overload of 'prepare_stable_SM_kernel'
matching 'void (*)(ctc_helper::identity<float, float>, float *, float *, int, int)' for 1st argument
inline void hipLaunchKernelGGL(F kernel, const dim3& numBlocks, const dim3& dimBlocks,
for following piece of C++ code
hipLaunchKernelGGL((prepare_stable_SM_kernel<ProbT, VT>),
dim3(grid_size),
dim3(NT),
0,
stream_,
ctc_helper::identity<ProbT>(),
probs_,
denoms_,
out_dim_,
num_elements);
where hipLaunchKernelGGL is defined as
template <typename... Args, typename F = void (*)(Args...)>
inline void hipLaunchKernelGGL(F kernel,
const dim3& numBlocks,
const dim3& dimBlocks,
std::uint32_t sharedMemBytes,
hipStream_t stream,
Args... args) {
// ...
// ...
}
and prepare_stable_SM_kernel is defined as
template <typename ProbT, int VT = 1, typename Op>
__global__ void prepare_stable_SM_kernel(Op f, ProbT* probs,
const ProbT* const col_max,
int alphabet_size,
int count) {
// ...
}
Anyone please help me by providing some hints to fix this problem.
This error was fixed by adding a third parameter ctc_helper::identity<ProbT> to prepare_stable_SM_kernel function
Ref https://github.com/harish2704/warp-ctc/commit/c7ec45febc9c0077ffa35932b3d11a05daf8bf7c#diff-1e372cfc8edab301b6c284e9db8dbf68
I want to do an array of OIS::Keys (int) and of std::function.
I have this :
struct UserCommands
{
OIS::KeyCode key;
std::function<bool(Worms *, const Ogre::FrameEvent& evt)> func;
};
UserInput input;
UserCommands usrCommands[] =
{
{
OIS::KC_A, std::bind(&input, &UserInput::selectBazooka)
},
};
But when I try to compile this I have this compile error :
In file included from includes/WormsApp.hh:5:0,
/src/main.cpp:2:
/includes/InputListener.hh:26:25: error: could not convert ‘std::bind(_Func&&, _BoundArgs&& ...) [with _Func = UserInput*; _BoundArgs = {bool (UserInput::*)(Worms*, const Ogre::FrameEvent&)}; typename std::_Bind_helper<std::__is_socketlike<_Func>::value, _Func, _BoundArgs ...>::type = std::_Bind<UserInput*(bool (UserInput::*)(Worms*, const Ogre::FrameEvent&))>](&UserInput::selectBazooka)’ from ‘std::_Bind_helper<false, UserInput*, bool (UserInput::*)(Worms*, const Ogre::FrameEvent&)>::type {aka std::_Bind<UserInput*(bool (UserInput::*)(Worms*, const Ogre::FrameEvent&))>}’ to ‘std::function<bool(Worms*, const Ogre::FrameEvent&)>’
OIS::KC_A, std::bind(&input, &UserInput::selectBazooka)
^
What have I done wrong ?
Using a lambda, would be like this (instead of std::bind())
[&](Worms*x, const Ogre::FrameEvent&y) { return input.selectBazooka(x,y); }
The first argument of std::bind is a callable object. In your case, that should be &UserInput::selectBazooka. The object to be associated with a call to that member function (&input) goes afterwards (you reversed this order). Still, you have to use placeholders for the missing parameters:
std::bind(&UserInput::selectBazooka, &input, std::placeholders::_1, std::placeholders::_2)
I am having trouble aliasing the function boost::make_iterator_range
(I would like to hide boost behind an alias in case this particular library gets adopted into the standard sometime in the future.)
Is there any way this can be made to work?
#include <boost/range/iterator_range.hpp>
void Foo()
{
}
template< typename T >
void Bar()
{ }
template< typename T >
void Bar(char c)
{ }
void (&FooAlias)() = Foo; // ok
void (&BarAlias)() = Bar<int>; // ok
// boost::iterator_range<const size_t*> (&MakeIterRangeAlias)(const size_t*,const size_t*) =
// boost::make_iterator_range<const size_t*>; // not ok
int main(int argc, char** argv)
{
const size_t v[] = { 3, 5, 1, 5, 29, 15 };
boost::iterator_range<const size_t*> r
= boost::make_iterator_range( std::begin( v ), std::end( v )); // want to alias this
return 0;
}
The error message is:
In file included from /usr/include/boost/iterator/iterator_categories.hpp:15:0,
from /usr/include/boost/iterator/detail/facade_iterator_category.hpp:7,
from /usr/include/boost/iterator/iterator_facade.hpp:14,
from /usr/include/boost/range/iterator_range_core.hpp:23,
from /usr/include/boost/range/iterator_range.hpp:13,
from sandbox.cpp:2:
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int* const> >’:
/usr/include/boost/range/iterator.hpp:63:63: instantiated from ‘boost::range_iterator<const long unsigned int* const>’
sandbox.cpp:20:10: instantiated from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int* const> >::f_ {aka struct boost::range_const_iterator<const long unsigned int*>}’
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int*> >’:
/usr/include/boost/range/iterator.hpp:63:63: instantiated from ‘boost::range_iterator<const long unsigned int*>’
sandbox.cpp:20:10: instantiated from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<false, boost::range_const_iterator<const long unsigned int*>, boost::range_mutable_iterator<const long unsigned int*> >::f_ {aka struct boost::range_mutable_iterator<const long unsigned int*>}’
sandbox.cpp:20:10: error: invalid initialization of non-const reference of type ‘void (&)(const size_t*, const size_t*) {aka void (&)(const long unsigned int*, const long unsigned int*)}’ from an rvalue of type ‘<unresolved overloaded function type>’
make: *** [sandbox] Error 1
Using function pointers is a suboptimal way alias a function. It is not as flexible as the original (it can no longer be a template) and you now need to know the exact signature of the function, which may or may not be stable.
Instead try this approach.
template< typename ... Args >
auto MakeIterRangeAlias( Args&& ... args ) -> decltype( /* copy return line here */ )
{
return boost::make_iterator_range( std::forward<Args>(args)... );
}
With almost no work on your part the alias supports the exact signature of the original. Even if it dramatically changes, you're still set. Further, unlike the function pointer approach the optimizer will be able to trivially inline MakeIterRangeAlias so that there is no runtime overhead.