Generalize the argument passed to boost::bind - c++

I am trying to write a generic struct MyCounter which uses boost::bind . What I am trying to do is to write MyCounter such a way that by changing its template argument type, I could bind to different methods. I was under the impression that if I pass something like MyThread::send as a template argument, I will be able to use it directly in bind(). Apparently I was wrong. Could you kindly help me with the alternatives? Thank you
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <vector>
#include <utility>
struct MyThread //simplified
{
void send1()
{
std::cout << "In Send1\n";
}
void send2()
{
std::cout << "In Send2\n";
}
};
struct Job //ignore me
{
Job(const unsigned int interval)
: _tChk(0)
, _tInterval(interval)
{}
void operator()(unsigned long nowSec)
{
if (nowSec > _tChk)
{
_functor();
_tChk += nowSec + _tInterval;
}
}
private:
unsigned long _tChk;
const unsigned int _tInterval;
protected:
boost::function<void()> _functor;
};
struct JobInvoker //ignore me
{
typedef boost::shared_ptr<Job> JobPtr;
JobInvoker(MyThread &myThread)
: _myThread(myThread)
{}
template<typename JOB>
void addJob(const unsigned int interval)
{
JobPtr job = boost::make_shared<JOB>(interval, _myThread);
_jobs.push_back(job);
}
void operator() (JobPtr job)
{
(*job)(_now.tv_sec);
}
void invoke(timeval now)
{
_now = now;
std::for_each(_jobs.begin(), _jobs.end(), *this);
}
timeval _now;
std::vector<JobPtr> _jobs;
MyThread &_myThread;
};
//my struggle
template<typename F>
struct MyCounter : public Job
{
MyCounter(const unsigned int interval, MyThread &myThread)
: Job(interval)
{
_functor = boost::bind(&F, &myThread); //<-- Error
}
};
int main()
{
MyThread t;
JobInvoker jobInvoker(t);
jobInvoker.addJob<MyCounter<MyThread::send1> >(2); //<-- Error
jobInvoker.addJob<MyCounter<MyThread::send2> >(2); //<-- Error
timeval now;//...
jobInvoker.invoke(timeval now)
return 0;
}
UPDATE:
compiled with:
g++ boost_f.cpp -lboost_system
we get the following errors:
boost_f.cpp: In constructor ‘MyCounter<F>::MyCounter(unsigned int, MyThread&)’:
boost_f.cpp:81:34: error: expected primary-expression before ‘,’ token
_functor = boost::bind(&F, &myThread); //<-- Error
^
boost_f.cpp: In function ‘int main()’:
boost_f.cpp:89:46: error: type/value mismatch at argument 1 in template parameter list for ‘template<class F> struct MyCounter’
jobInvoker.addJob<MyCounter<MyThread::send1> >(2); //<-- Error
^
boost_f.cpp:89:46: error: expected a type, got ‘MyThread::send1’
boost_f.cpp:89:51: error: no matching function for call to ‘JobInvoker::addJob(int)’
jobInvoker.addJob<MyCounter<MyThread::send1> >(2); //<-- Error
^
boost_f.cpp:89:51: note: candidate is:
boost_f.cpp:52:10: note: template<class JOB> void JobInvoker::addJob(unsigned int)
void addJob(const unsigned int interval)
^
boost_f.cpp:52:10: note: template argument deduction/substitution failed:
boost_f.cpp:89:51: error: template argument 1 is invalid
jobInvoker.addJob<MyCounter<MyThread::send1> >(2); //<-- Error
^
boost_f.cpp:90:46: error: type/value mismatch at argument 1 in template parameter list for ‘template<class F> struct MyCounter’
jobInvoker.addJob<MyCounter<MyThread::send2> >(2); //<-- Error
^
boost_f.cpp:90:46: error: expected a type, got ‘MyThread::send2’
boost_f.cpp:90:51: error: no matching function for call to ‘JobInvoker::addJob(int)’
jobInvoker.addJob<MyCounter<MyThread::send2> >(2); //<-- Error
^
boost_f.cpp:90:51: note: candidate is:
boost_f.cpp:52:10: note: template<class JOB> void JobInvoker::addJob(unsigned int)
void addJob(const unsigned int interval)
^
boost_f.cpp:52:10: note: template argument deduction/substitution failed:
boost_f.cpp:90:51: error: template argument 1 is invalid
jobInvoker.addJob<MyCounter<MyThread::send2> >(2); //<-- Error
^
boost_f.cpp:92:29: error: expected primary-expression before ‘now’
jobInvoker.invoke(timeval now)

Like the error says, a member function isn't a type, so it can't be used for a template type parameter.
Instead, you need to use a non-type parameter:
template<void(MyThread::*F)()>
struct MyCounter : public Job
{
MyCounter(const unsigned int interval, MyThread &myThread)
: Job(interval)
{
_functor = boost::bind(F, &myThread);
}
};
Live Example
Note that I made F a pointer to a member function of MyThread instead of a typename.

Related

CTAD doesn't work with defaulted template arguments?

Compare the following case when I have a class object that takes a vector. The non-deduced parameter T can be substituted fine with the default template argument:
#include <vector>
template <typename T = int>
struct container
{
container(std::vector<T> vec) {}
};
int main()
{
container C = std::vector{1,2,3,4,5};
}
This is not the case for my class which is a bit more complicated (CompilerExplorer):
#include <cstdio>
#include <initializer_list>
#include <variant>
template <size_t> struct obj;
template<size_t Vs>
using val = std::variant<std::monostate, int, struct obj<Vs>>;
template <size_t Vs = 0>
struct obj
{
obj() = default;
obj(std::initializer_list<val<Vs>> init) {
printf("initializer of object called, Vs = %d\n", Vs);
}
};
template <size_t Vs = 0>
struct container : public obj<Vs>
{
container(obj<0> init) {}
};
int main()
{
container<5> some_container = obj{1,2,5,2,obj{1,2,33},2,2};
}
This fails with the following error:
<source>: In function 'int main()':
<source>:29:57: error: class template argument deduction failed:
29 | container<5> some_container = obj{1,2,5,2,obj{1,2,33},2,2};
| ^
<source>:29:57: error: no matching function for call to 'obj(int, int, int)'
<source>:14:5: note: candidate: 'template<long unsigned int Vs> obj(std::initializer_list<std::variant<std::monostate, int, obj<Vs> > >)-> obj<<anonymous> >'
14 | obj(std::initializer_list<val<Vs>> init) {
| ^~~
But it works when I supplement the template specialization obj<0> in the instantiation of the container (in main). Any ideas why this doesn't work for my class and how I can fix it? I don't want to force the user to specify the template each time.
This problem already exists in the simpler case of just
auto o = obj{1,2,33};
which yields this error:
<source>:29:24: error: class template argument deduction failed:
29 | auto o = obj{1,2,33};
| ^
<source>:29:24: error: no matching function for call to 'obj(int, int, int)'
<source>:14:5: note: candidate: 'template<long unsigned int Vs> obj(std::initializer_list<std::variant<std::monostate, int, obj<Vs> > >)-> obj<<anonymous> >'
14 | obj(std::initializer_list<val<Vs>> init) {
| ^~~
<source>:14:5: note: template argument deduction/substitution failed:
<source>:29:24: note: mismatched types 'std::initializer_list<std::variant<std::monostate, int, obj<Vs> > >' and 'int'
29 | auto o = obj{1,2,33};
So, the compiler is unable to deduce, that the three ints should be an initializer list. If you add extra braces around them, the compiler recognizes that this should actually be a single list argument instead of three separate ones and it works:
auto o = obj{{1,2,33}};
This also carries over to the more complicated case:
container some_container = obj{{1,2,5,2,obj{{1,2,33}},2,2}};

How to handle nested type template in C++

Can anyone help me with this errors. When i compile this simple program
#include<queue>
using namespace std;
template<typename Queue>
int qtest(Queue & queue,typename Queue::Type item)
{
return 0;
}
int main()
{
std::queue<int> q;
int t = qtest(q,3);
}
I get the errors like below
In function 'int main()':
error: no matching function for call to 'qtest(std::queue<int>&, int)'
note: candidate is:
note: template<class Queue> int qtest(Queue&, typename Queue::Type)
note: template argument deduction/substitution failed:
In substitution of 'template<class Queue> int qtest(Queue&, typename Queue::Type) [with
Queue = std::queue<int>]':
required from here
error: no type named 'Type' in 'class std::queue<int>'
warning: unused variable 't' [-Wunused-variable]
std::queue doesn't have a member type called Type. That's what the compiler is telling us. I'm guessing what you're looking for is std::queue<int>::value_type.
template<typename Queue>
int qtest(Queue & queue,typename Queue::value_type item)
{
return 0;
}
Reference: cppreference

Boost phoenix member function operator fails to compile if function has overload

I want to use Boost phoenix member function operator for the class function that has overloads, like here.
The following example fails:
#include <boost/phoenix/phoenix.hpp>
#include <boost/phoenix/operator.hpp>
using namespace std;
using namespace boost::phoenix::placeholders;
struct A
{
int m_id = 1;
int func() const { return 1; }
void func(int id) { m_id = id; }
};
int main()
{
A *a = new A;
auto retVal = (arg1->*&A::func)()(a);
return 0;
}
With error:
In function 'int main()': 17:21: error: no match for 'operator->*'
(operand types are 'const type {aka const
boost::phoenix::actor<boost::proto::exprns_::basic_expr<boost::proto::tagns_::
tag::terminal, boost::proto::argsns_::term<boost::phoenix::argument<1> >, 0l>
>}' and '<unresolved overloaded function type>') 17:21: note: candidate is: In
file included from /usr/include/boost/phoenix/operator/arithmetic.hpp:13:0,
from /usr/include/boost/phoenix/operator.hpp:13, from /usr/include/boost
/phoenix/phoenix.hpp:13, from 1: /usr/include/boost/proto/operators.hpp:295:9:
note: template<class Left, class Right> const typename
boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain,
boost::proto::detail::not_a_grammar,
boost::mpl::or_<boost::proto::is_extension<Arg>,
boost::proto::is_extension<Right> >, boost::proto::tagns_::tag::mem_ptr, const
Left&, const Right&>::type boost::proto::exprns_::operator->*(Left&&,
Right&&) BOOST_PROTO_DEFINE_OPERATORS(is_extension, deduce_domain) ^
/usr/include/boost/proto/operators.hpp:295:9: note: template argument
deduction/substitution failed: 17:28: note: couldn't deduce template parameter
'Right'
However, if I comment the line void func(int id) { m_id = id; } out, it works as expected.
How can I tell which of the overloads to use?
Handling (member) function pointers to overload sets is always a pain. You need to cast the address to a pointer that has the exact signature of the desired overload. In your case, for selection int A::func():
auto retVal = (arg1->*static_cast<int (A::*)() const>(&A::func))()(a);
or a bit more readable, but basically the same:
const auto memFctPtr = static_cast<int (A::*)() const>(&A::func);
auto retVal = (arg1->*memFctPtr)()(a);

Pass a templatized type to a member function in C++

I'm trying to write a member function that can instantiate an object of a custom type (templatized), initializing its const& member to a local object of the function.
This is consistent since the lifetime of the custom type object is the same as the local_object.
The objective is caching some metadata of the local object because they don't change during its lifetime. The operator() (or any member function) computes some values, then used later in func, and the objective is offering a hook to change the behaviour of func.
Please no polymorphic solutions (currently used) due to (profiled) slowness.
This is a M(N)WE:
#include <vector>
class cls {
public:
template <typename Custom> int func() {
std::vector<int> local_object{0, 14, 32};
Custom c(local_object, 42);
return c();
}
};
template<typename AType> class One {
public:
One(const AType& obj, const int n): objref(obj), param(n), member_that_should_depend_on_objref(obj.size()) {}
int operator()() { return 42; }
private:
const AType& objref;
const int param;
float member_that_should_depend_on_objref;
};
template<typename AType> class Two {
public:
Two(const AType& obj, const int n): objref(obj), param(n), other_member_that_should_depend_on_objref(obj.empty()), other_dependent_member(obj.back()) {}
int operator()() { return 24; }
private:
const AType& objref;
const int param;
bool other_member_that_should_depend_on_objref;
int other_dependent_member;
};
int main() {
cls myobj;
auto a = myobj.func<One>();
auto b = (myobj.func<Two>)();
}
G++ 5.3.0 says
tmp.cpp: In function 'int main()':
tmp.cpp:34:30: error: no matching function for call to 'cls::func()'
auto a = myobj.func<One>();
^
tmp.cpp:4:36: note: candidate: template<class Custom> int cls::func()
template <typename Custom> int func() {
^
tmp.cpp:4:36: note: template argument deduction/substitution failed:
tmp.cpp:35:32: error: no matching function for call to 'cls::func()'
auto b = (myobj.func<Two>)();
^
tmp.cpp:4:36: note: candidate: template<class Custom> int cls::func()
template <typename Custom> int func() {
^
tmp.cpp:4:36: note: template argument deduction/substitution failed:
Clang++ 3.7.1 says:
tmp.cpp:34:20: error: no matching member function for call to 'func'
auto a = myobj.func<One>();
~~~~~~^~~~~~~~~
tmp.cpp:4:36: note: candidate template ignored: invalid explicitly-specified argument for template
parameter 'Custom'
template <typename Custom> int func() {
^
tmp.cpp:35:21: error: no matching member function for call to 'func'
auto b = (myobj.func<Two>)();
~~~~~~~^~~~~~~~~~
tmp.cpp:4:36: note: candidate template ignored: invalid explicitly-specified argument for template
parameter 'Custom'
template <typename Custom> int func() {
^
2 errors generated.
auto a = myobj.func<One>();
is wrong since One is a class template, not a class. Use
auto a = myobj.func<One<SomeType>>();
It's not clear from your code what SomeType should be.
Update
If you want to use:
auto a = myobj.func<One>();
you need to change func to use a template template parameter:
class cls {
public:
template <template <class> class Custom > int func() {
std::vector<int> local_object{0, 14, 32};
Custom<std::vector<int>> c(local_object, 42);
return c();
}
};
Perhaps that was your intention.

C++ typedef function definition as a class member to use later for function pointer?

I need to have a class that stores a function definition/prototype as a class member in order to use it later to get function pointers based on that definition.
#include <cstdlib>
#include <cstdio>
#include <functional>
template<typename... Ts>
class Function;
template <typename R>
class Function<R>
{
public:
using FuncType = R (*) ();
Function()
{
printf("R()\n");
}
};
template <typename R, typename... A>
class Function<R, A...>
{
public:
using FuncType = R (*) (A...);
Function()
{
printf("R(A)\n");
}
};
void fn1(int i) { printf("Called fn1: %d\n", i); }
void fn2(int i, float f) { printf("Called fn2: %d, %f\n", i, f); }
void fn3() { printf("Called fn3: N/A \n"); }
int main(int argc, char **argv)
{
Function<void, int> myFuncX;
Function<void, int, float> myFuncY;
Function<void> myFuncZ;
myFuncX.FuncType mf1 = fn1;
myFuncY.FuncType mf2 = fn2;
myFuncZ.FuncType mf3 = fn3;
fn1(244);
fn2(568, 1.891);
fn3();
return EXIT_SUCCESS;
}
Objects are unknown until runtime which is the reason I need them to be class members. They're stored in an std::map and I need to be able to get a specific item from the map and to use it's function definition/prototype to store the pointer of a function.
But I always get this kind of error:
||=== Build: Win32 Release in Sandbox (compiler: GNU GCC Compiler) ===
.\src\testdummy.cpp||In function 'int main(int, char**)':
.\src\testdummy.cpp|42|error: invalid use of 'using FuncType = void (*)(int)'
.\src\testdummy.cpp|42|error: expected ';' before 'mf1'
.\src\testdummy.cpp|43|error: invalid use of 'using FuncType = void (*)(int, float)'
.\src\testdummy.cpp|43|error: expected ';' before 'mf2'
.\src\testdummy.cpp|44|error: invalid use of 'using FuncType = void (*)()'
.\src\testdummy.cpp|44|error: expected ';' before 'mf3'
||=== Build failed: 6 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===
I've tried with std::function, typedef etc. Why do I get this?
This is wrong:
myFuncX.FuncType mf1 = fn1;
You can't use a type alias as a normal member - it's a declaration inside class' scope, similar as typedefs. This will work:
decltype(myFuncX)::FuncType mf1 = fn1;