I am sharing with you an issue that I got with a class using variadic function parameters. It is the class Thread shown in the following code. It is a wrapper of std::thread in order to use the function pattern.
I wanted to use polymorphism with this function in inheriting the class Thread into a new class, Functor, but gcc returns the errors bellow:
#include <thread>
#include <iostream>
using namespace std;
template<class... Args>
class Thread
{
public:
virtual void operator()(Args...) = 0;
void run(Args... args)
{
std::thread t(std::forward< Thread<Args...> >(*this), std::forward<Args>(args)...);
t.join();
}
};
template<class... Args>
class Functor : public Thread<Args...>
{
public:
// generates the errors bellow
virtual void operator()(Args... /*args*/)
{
}
// doesnot work since the pure virtual function wants another prototype of function.
// void operator()(int)
// {
// }
};
int main()
{
int a = 12;
Functor<int> f;
f.run(ref(a));
return 0;
}
from t-Thread-args2.cpp:1:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple: In instantiation of ‘struct std::_Head_base, false>’:
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:215:12: required from ‘struct std::_Tuple_impl, int>’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:507:11: required from ‘class std::tuple, int>’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/functional:1601:39: required from ‘struct std::_Bind_simple(int)>’
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/thread:133:9: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = Thread; _Args = {int}]’
t-Thread-args2.cpp:14:83: required from ‘void Thread::run(Args ...) [with Args = {int}]’
t-Thread-args2.cpp:42:17: required from here
/usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../include/c++/4.7.2/tuple:166:13: error: cannot declare field ‘std::_Head_base, false>::_M_head_impl’ to be of abstract type ‘Thread’
t-Thread-args2.cpp:7:7: note: because the following virtual functions are pure within ‘Thread’:
t-Thread-args2.cpp:10:18: note: void Thread::operator()(Args ...) [with Args = {int}]
I dont really understand the error since the pure virtual function was well defined in the deriveted class. However, in moving the function run() into the derivated class (Functor) it works.
Thanks in advance,
Caner
As per [thread.thread.constr]§3, the type of the first argument of the std::thread constructor is F&&, with the requirement that F is MoveConstructible. In your case, F is Thread, which is not MoveConstructible.
In other words, the std::thread needs to store the functor by value, and you're forwarding the functor as Thread, which is abstract.
The problem is:
std::forward< Thread<Args...> >(*this)
which tries to copy the Thread sub-object. Luckily it's abstract, so you get a compile error rather than unexpected runtime behaviour.
You want a reference wrapper instead:
std::ref(*this)
I considered the multiple advice provided by the participants to this topic including the use of std::ref and would like to share with you the working code version solving the issues I got with the previous code.
#include <thread>
#include <iostream>
using namespace std;
template<class... Args>
class Thread
{
public:
virtual void operator()(Args...) = 0;
void run(Args... args)
{
std::thread t(std::ref(*this), args...);
t.join();
}
};
template<class... Args>
class Functor : public Thread<Args...>
{
public:
void operator()(int)
{
while (1)
{
cout << "42 "; cout.flush();
}
}
};
int main()
{
int a = 12;
Functor<int> f;
f.run(ref(a));
return 0;
}
Thanks again.
Related
I'm trying to call a function from within a template function inside a template.
The call itself, however, doesn't compile, instead I get the following error:
/home/alexis/tmp/b.cpp: In instantiation of ‘bool callback_manager<C>::call_member(F, ARGS ...) [with F = bool (main()::foo::*)(int, int, int); ARGS = {int, int, int}; C = std::vector<std::shared_ptr<main()::foo> >]’:
/home/alexis/tmp/b.cpp:43:47: required from here
/home/alexis/tmp/b.cpp:15:19: error: no match for ‘operator->*’ (operand types are ‘std::shared_ptr<main()::foo>’ and ‘bool (main()::foo::*)(int, int, int)’)
if(!(c->*func)(&args...))
~~^~~~~~~~
Here is a simplified version of the code I'm trying to compile:
#include <memory>
#include <vector>
template<typename C>
class callback_manager
{
public:
template<typename F, typename ... ARGS>
bool call_member(F func, ARGS ... args)
{
C callbacks(f_callbacks);
for(auto c : callbacks)
{
if(!(c->*func)(args...))
{
return false;
}
}
return true;
}
private:
C f_callbacks;
};
int main()
{
class foo
{
public:
typedef std::shared_ptr<foo> pointer_t;
typedef std::vector<pointer_t> vector_t;
bool the_callback(int, int, int)
{
return true;
}
};
callback_manager<foo::vector_t> m;
m.call_member(&foo::the_callback, 5, 13, 7);
return 1;
}
Looking at the parameters, it seems to be that both are correct:
std::shared_ptr<main()::foo>
and
bool (main()::foo::*)(int, int, int)
The fact is that the ->* operator doesn't work with the std::shared_ptr<>.
The solution is to retrieve the bare pointer like so:
if(!(c.get()->*func)(args...)) ...
It then compiles as expected.
You can also rewrite it as follow, which I think is more cryptic:
if(!(*c).*func)(args...)) ...
(i.e. the shared_ptr::operator * () function returns the pointed to object held by the shared pointer, hence the .* operator is used in this case.)
Replace
if(!(c->*func)(args...))
with
if(!(std::cref(func)(c, args...)))
to use the INVOKE machinery of C++. Or use std::invoke directly.
INVOKE concept in the standard, and std::invoke, where designed to work with pmfs and smart pointers.
Meanwhile, ->* isn't overloaded by smart pointers. So direct use like that won't work.
As a side benefit, now a non member function can be passed in as the func.
I am trying to understand std::bind(). I am trying to understand the code in the post https://riptutorial.com/cplusplus/example/7541/std--function-used-with-std--bind.
Code is as below.
#include <iostream>
#include <functional>
using namespace std;
class A
{
public:
std::function<void(int, const std::string&)> m_CbFunc = nullptr;
void foo()
{
if (m_CbFunc)
{
m_CbFunc(100, "event fired");
}
}
};
class B
{
public:
B(int x) : y(x)
{
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2);
anObjA.m_CbFunc = aFunc;
}
void eventHandler(int i, const std::string& s)
{
std::cout << s << ": " << i << std::endl;
}
void DoSomethingOnA()
{
anObjA.foo();
}
int y;
A anObjA;
};
int main(int argc, char *argv[])
{
B anObjB(4);
anObjB.DoSomethingOnA();
}
I couldn't understand why we are using this in bind call
auto aFunc = std::bind(&B::eventHandler, this, std::placeholders::_1, std::placeholders::_2)
eventHandler is taking 2 parameters and we are binding with placeholders. Not sure why do we need to pass this. If I remove this, I am getting below error.
/usr/include/c++/6/functional:1286:7: error: static assertion failed: Wrong number of arguments for pointer-to-member
static_assert(_Varargs::value
^~~~~~~~~~~~~
main.cpp: In constructor ‘B::B(int)’:
main.cpp:34:27: error: no match for ‘operator=’ (operand types are ‘std::function&)>’ and ‘std::_Bind&)>(std::_Placeholder<1>, std::_Placeholder<2>)>’)
anObjA.m_CbFunc = aFunc;
^~~~~
In file included from main.cpp:10:0:
/usr/include/c++/6/functional:1929:7: note: candidate: std::function<_Res(_ArgTypes ...)>& std::function<_Res(_ArgTypes ...)>::operator=(const std::function<_Res(_ArgTypes ...)>&) [with _Res = void; _ArgTypes = {int, const std::basic_string, std::allocator >&}]
operator=(const function& __x)
^~~~~~~~
The this is needed because eventHandler() is not a static method. std::bind() is used specifically when you want to use non-static methods of your class.
Note that personally, I find it ugly and don't like using it. I use lambdas instead.
anObjA.m_CbFunc = [=](int i, const std::string&s) { eventHandler(i,s); };
Even though the syntax for lambdas is kind of ugly, I don't think it's as ugly or obscure as bind. But that's just my preference.
I need to queue task as function pointers. The argument for function pointer is a list of parameters and a callback.
I created a class which stores theses tasks. Now I need to write a template method which takes a function pointer, parameters and callback.
I tried creating below class, but is not compiling...
#include <iostream>
#include <vector>
#include <functional>
#include <memory>
class TaskScheduler {
public:
TaskScheduler() = default;
virtual ~TaskScheduler() {}
template <typename... TParam>
struct Callback {
using Type = std::function<void(TParam...)>;
};
template<typename TCallback, typename... TRequestParam>
void queue(void (*requestFunction)(TRequestParam..., typename TCallback::Type),
TRequestParam... args, typename TCallback::Type callback) {
doQueue([this, requestFunction, args..., callback](){
requestFunction(args..., callback);
});
}
void fire() {
for (auto task: mTasks) {
task();
}
}
protected:
void doQueue(std::function<void()> task) {
mTasks.push_back(task);
}
std::vector<std::function<void()>> mTasks;
};
class Test1 {};
class Test2 {};
class Test3 {};
void function1(Test1 *a1, std::shared_ptr<Test2> a2, std::function<void(std::shared_ptr<Test2>)> a3) {
}
int main(int, char **) {
TaskScheduler ns;
Test1 *test1Ptr = 0;
auto test2Sptr = std::make_shared<Test2>();
std::function<void(std::shared_ptr<Test2>)> callback = [](std::shared_ptr<Test2>){};
ns.queue<TaskScheduler::Callback<std::shared_ptr<Test2>>, Test1 *, std::shared_ptr<Test2>>(&function1, test1Ptr, test2Sptr, callback);
ns.fire();
}
With clang I get the error,
mtest.cc:55:8: error: no matching member function for call to 'queue'
ns.queue<TaskScheduler::Callback<std::shared_ptr<Test2>>, Test1 *, std::shared_ptr<Test2>>(&function1, test1Ptr, test2Sptr, callback);
~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mtest.cc:17:10: note: candidate template ignored: failed template argument deduction
void queue(void (*requestFunction)(TRequestParam..., typename TCallback::Type),
I have a class MyVariable that holds an object and does some extra work when this object has to be modified. Now I want to specialize this to MyContainer for container objects that perform this extra work only when the container itself is modified (e.g. via push_back()) but not its elements.
My code looks like this:
template<typename T>
class MyVariable
{
public:
//read-only access if fine
const T* operator->() const {return(&this->_element);}
const T& operator*() const {return( this->_element);}
//write acces via this function
T& nonconst()
{
//...here is some more work intended...
return(this->_element);
}
protected:
T _element;
};
template<typename T>
class MyContainer: public MyVariable<T>
{
public:
template<typename Arg>
auto nonconst_at(Arg&& arg) -> decltype(MyVariable<T>::_element.at(arg))
{
//here I want to avoid the work from MyVariable<T>::nonconst()
return(this->_element.at(arg));
}
};
#include <vector>
int main()
{
MyContainer<std::vector<float>> container;
container.nonconst()={1,3,5,7};
container.nonconst_at(1)=65;
}
However, with GCC4.7.2 I get an error that I cannot access _element because it is protected.
test1.cpp: In substitution of 'template<class Arg> decltype (MyVariable<T>::_element.at(arg)) MyContainer::nonconst_at(Arg&&) [with Arg = Arg; T = std::vector<float>] [with Arg = int]':
test1.cpp:39:25: required from here
test1.cpp:17:4: error: 'std::vector<float> MyVariable<std::vector<float> >::_element' is protected
test1.cpp:26:7: error: within this context
test1.cpp: In member function 'decltype (MyVariable<T>::_element.at(arg)) MyContainer<T>::nonconst_at(Arg&&) [with Arg = int; T = std::vector<float>; decltype (MyVariable<T>::_element.at(arg)) = float&]':
test1.cpp:17:4: error: 'std::vector<float> MyVariable<std::vector<float> >::_element' is protected
test1.cpp:39:25: error: within this context
test1.cpp: In instantiation of 'decltype (MyVariable<T>::_element.at(arg)) MyContainer<T>::nonconst_at(Arg&&) [with Arg = int; T = std::vector<float>; decltype (MyVariable<T>::_element.at(arg)) = float&]':
test1.cpp:39:25: required from here
test1.cpp:17:4: error: 'std::vector<float> MyVariable<std::vector<float> >::_element' is protected
test1.cpp:26:7: error: within this context
What's going on here?
The problem does seem to be specific to the use of decltype() - if I explicitly declare nonconst_at() to return T::value_type&, thus:
template<typename Arg>
typename T::value_type& nonconst_at(Arg&& arg)
then GCC 4.8.2 compiles it with no warnings or errors. That's fine for standard containers, but obviously doesn't help every situation.
Actually calling this->_element.at(arg) isn't a problem: I can omit the trailing return type and have the compiler infer it:
template<typename Arg>
auto& nonconst_at(Arg&& arg)
{
//here I want to avoid the work from MyVariable<T>::nonconst()
return this->_element.at(std::forward<Arg>(arg));
}
with just a warning (which disappears with -std=c++1y) and no errors. I still need the this->, because _element is a member of a dependent base class (thanks, Simple).
EDIT - additional workaround:
As you're only interested in the type of the return value of T::at(), you can use the decltype of calling it with any T you like, even a null pointer:
template<typename Arg>
auto nonconst_at(Arg&& arg) -> decltype(((T*)nullptr)->at(arg))
{
//here I want to avoid the work from MyVariable<T>::nonconst()
return this->_element.at(std::forward<Arg>(arg));
}
It's ugly, but it does seem to work.
I have a compile error when using std::function in a templated member function, the following code is a simple example:
#include <functional>
#include <memory>
using std::function;
using std::bind;
using std::shared_ptr;
class Test {
public:
template <typename T>
void setCallback(function<void (T, int)> cb);
};
template <typename T>
void Test::setCallback(function<void (T, int)> cb)
{
// do nothing
}
class TestA {
public:
void testa(int a, int b) { }
};
int main()
{
TestA testA;
Test test;
test.setCallback(bind(&TestA::testa, &testA, std::placeholders::_1, std::placeholders::_2));
return 0;
}
And come with the following compile error:
testtemplate.cpp: In function ‘int main()’:
testtemplate.cpp:29:92: error: no matching function for call to
‘Test::setCallback(std::_Bind_helper)(int, int),
TestA, const std::_Placeholder<1>&, const
std::_Placeholder<2>&>::type)’
testtemplate.cpp:29:92: note: candidate is: testtemplate.cpp:10:7:
note: template void Test::setCallback(std::function)
testtemplate.cpp:10:7: note: template argument
deduction/substitution failed:
testtemplate.cpp:29:92: note: ‘std::_Bind(TestA*, std::_Placeholder<1>,
std::_Placeholder<2>)>’ is not derived from ‘std::function’
I'm using C++11 and g++ 4.7
To figure out the problem let separate statements:
auto f = bind(&TestA::testa, &testA, _1, _2); // OK
test.setCallback(f); // <<--- Error is here
setCallback needs to know type of T and it can't deduce it from f, so give it a type
test.setCallback<TYPE>(f); // TYPE: int, float, a class, ...
You can make type deduction work with some variant of:
template<typename CALLBACK>
void setCallback(CALLBACK cb) {
typedef CALLBACK::first_argument_type T;
static_assert(is_same_type<CALLBACK,function<void(T,int)>>::value);
...
}
This way CALLBACK can be determined by looking at the argument. It might get into trouble if bind doesn't actually return a std::function but rather something that can be cast as one. I'm not sure.