I can't figure out whats wrong with the code here, so I was hopinh someone could help me out:
In a header file, I define the following functions
void GenLiveVar(const instr_ptr instr, std::vector<ResultBase*> &list);
void KillLiveVar(const instr_ptr instr, std::vector<ResultBase*> &list);
In a class header file, I define this typedef:
typedef boost::function<void(instr_ptr, std::vector<ResultBase*>) > GenFunction;
inside the class, I have two instances of GenFunction
GenFunction Gen;
GenFunction Kill;
And I assign into them as follows
void DataFlowSolver::SetGenFunction(GenFunction &func)
{
Gen = func;
}
void DataFlowSolver::SetKillFunction(GenFunction &func)
{
Kill = func;
}
later in my program, I assign to gen as follows:
blockSolver.SetGenFunction(GenLiveVar);
where GenLiveVar is the function mentioned earlier and blockSolver is an instance of the class holding the Gen/Kill. Inside blockSolver, I do the following:
std::vector<ResultBase*> genList;
Gen(currentBlock->GetInstrPtr(i), &genList);
and GetInstrPtr is defined as const instr_ptr GetInstrPtr(int index);
It generates the follwoing error (sorry for length)
no match for call to '(GenFunction) (const instr_ptr, std::vector<ResultBase*, std::allocator<ResultBase*> >*)'
/nfs/ug/homes-2/r/rileyjon/ece540/Final/boost/function/function_template.hpp:1007:
note: candidates are: typename boost::function2<R, T1, T2>::result_type boost::function2<R, T1, T2>::operator()(T0, T1) const [with R = void, T0 = boost::shared_ptr<Instruction>,
T1 = std::vector<ResultBase*, std::allocator<ResultBase*> >
]
I dont really understand why this is a problem: the types are definitely the same. Some help would be appreciated. Thanks
The types are definitely not the same.
The argument you are passing is of type std::vector<ResultBase*>* (a pointer):
Gen(currentBlock->GetInstrPtr(i), &genList);
^
The corresponding parameter is of type std::vector<ResultBase*> (a value):
boost::function<void(instr_ptr, std::vector<ResultBase*>)>
^
Also note the mismatch in parameter types between the boost::function, which takes the second argument by value, and the two functions you assign to it, which take their second arguments by reference. This probably won't give you the behavior you expect.
Related
I have a class Frobnicator that handles various requests.
class Frobnicator
{
public:
// Handlers are member functions.
// They optionally take some input. They optionally return some output. But they always take the context!
// There are more types than just int involved, but it's always just one input or void, and one output or void.
void performSomething(Context* context) { /* ... */ } // Takes void, returns void
void setSomething (Context* context, int input) { /* ... */ } // Takes int , returns void
int getSomething (Context* context) { /* ... */ } // Takes void, returns int
int convertSomething(Context* context, int input) { /* ... */ } // Takes int , returns int
template<typename TResult, typename TParameter>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*, TParameter))
{
// The external API actually wants a callback that takes and returns JSON. We give it a lambda that does the conversion and calls the actual member function.
// The identifier tells the external API which callback to call for which request. It's not relevant for this question, just to show the idea. Think of something like a REST API.
someExternalApiThatWantsJson.registerHandler(identifier, [&](Context* context, Json input)
{
// Idealy, this would be a one-liner.
//return Json::convertFrom((this->*handler)(context, input.convertTo<TParameter>()));
// But calling Json.convertTo<void>() and Json::convertFrom(void) does not work automagically anyways, so we need to split it up manually:
Json result;
if constexpr (std::is_same<TResult, void>::value)
if constexpr (std::is_same<TParameter, void>::value) (this->*handler)(context ) ; // Takes void, returns void
else (this->*handler)(context, input.convertTo<TParameter>()) ; // Takes something, returns void
else
if constexpr (std::is_same<TParameter, void>::value) result = Json::convertFrom((this->*handler)(context )); // Takes void, returns something
else result = Json::convertFrom((this->*handler)(context, input.convertTo<TParameter>())); // Takes something, returns something
return result;
});
}
// Set up the handlers.
void setup()
{
// The problem is that some of these calls don't work:
registerHandler ("PerformSomething", &Frobnicator::performSomething); // "failed template argument deduction"
registerHandler<void, void>("PerformSomething", &Frobnicator::performSomething); // Trying to specify the types explicitly: "substitution failure [with TResult = void, TParameter = void]: argument may not have 'void' type"
registerHandler ("SetSomething" , &Frobnicator::setSomething); // Compiles fine
registerHandler ("GetSomething" , &Frobnicator::getSomething); // "failed template argument deduction"
registerHandler<int , void>("GetSomething" , &Frobnicator::getSomething); // Trying to specify the types explicitly: "substitution failure [with TResult = int, TParameter = void]: argument may not have 'void' type"
registerHandler ("ConvertSomething", &Frobnicator::convertSomething); // Compiles fine
}
};
TResult can be int or void and it works fine. But it only works when TParameter isn't void.
How can I make registerHandler also accept pointers to functions that take no arguments?
The idea is to have the member functions' signatures very clean and the calls to registerHandler mostly clean. So giving performSomething and getSomething a dummy parameter is out of the question. Manually specifying the types when calling registerHandler is ugly but I'll accept it, if it's necessary.
The body of registerHandler is relatively short and mostly deals with distinguishing void from non-void anyways, so providing a specialization for when TParameter is void would be a fine solution:
template<typename TResult>
void registerHandler<TResult, void>(std::string identifier, TResult(Frobnicator::* handler)(Context*))
Except that "function template partial specialization is not allowed".
Use template parameter pack to deal with void / non-void cases, since the number of arguments is indetermined (1 or 2).
template<typename TResult, typename... TParameter>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*, TParameter...))
The second parameter accepts a pointer to member function whose the first argument is required to be Context*, that's it.
Then,
void setup()
{
registerHandler ("PerformSomething", &Frobnicator::performSomething);
registerHandler ("SetSomething" , &Frobnicator::setSomething);
registerHandler ("GetSomething" , &Frobnicator::getSomething);
registerHandler ("ConvertSomething", &Frobnicator::convertSomething);
}
The implementation of registerHandler may also need some changes, the std::is_same_v<TParameter, void> can be replaced by sizeof...(TParameter) == 0.
Demo
Well. Sometimes you waste an hour because you narrowly miss a solution. Just don't make it a specification:
template<typename TResult>
void registerHandler(std::string identifier, TResult(Frobnicator::* handler)(Context*))
But!: This is a valid solution for me, but it would be nice to have a solution that does not require duplicating almost the entire function body. So better answers are absolutely welcome!
What I would do is follow the 0 1 infinity rule and write infinity instead of 2 cases.
Support any number of arguments. Map to tuples. Empty tuples for 0, mono for 1, etc.
Then the conversion code should work naturally. You can bind the call to be (take tuple, return tuple), then write the input/output code to handle 0, 1, or n from/to json.
Now the json function call logic no longer cares about void. The packing unpacking does. And the code that calls the raw function from tuples and packs it into a tuple return does.
template<class F>
auto packresult(F&&f){
if constexpr(f() is void)
f()
return tuple<>{};
else if constexpr(f returns a tuple)
return f();
else
return std::make_tuple(f());
}
Now you do the same for inputs
auto unpackargs(auto&&f){
return [f](auto&&tup){
return std::apply(f, tup);
}
}
which makes your code look like:
converttupletojson(packresult(bind(unpackargs(bind this to method), getargsfromjson<Args...>())))
and viola, the most surprising musical instrument.
I am trying to use an Arduino library and to use one of it's functions as a parameter in my own function, but I don't know how can I do that.
I tried the code below but I get an error.
Any help will be appreciated.
P.S: I do not have an option to use auto keyword.
using namespace httpsserver;
HTTPServer Http;
typedef void (*Register)(HTTPNode*); // My typedef
Register Node = Http.registerNode;
When I am trying to call Node (...), I get the error below.
Cannot convert 'httpsserver::ResourceResolver::registerNode'
from type 'void (httpsserver::ResourceResolver::)(httpsserver::HTTPNode*)'
to type 'Register {aka void (*)(httpsserver::HTTPNode*)}'
How can I create a function pointer for the type :
'void (httpsserver::ResourceResolver::)(httpsserver::HTTPNode*)'
I want to use it as a parameter in another function:
// My Declaration
void Get(void(*Register)(httpsserver::HTTPNode*), const std::string& path);
// Usage
Get (Http.registerNode(...), ""); // Like so
How can I do that?
A member function pointer is not a function pointer.
typedef void (httpsserver::*Register)(HTTPNode*); // My typedef
Register Node = &httpsserver::registerNode;
usage:
void Get(void(httpsserver::*Register)(httpsserver::HTTPNode*), const std::string& path);
Get (&httpsserver::registerNode, "");
you have to pass the httpsserver::HTTPNode* into Register within Get.
If you want to bind the arguments to the function object and call it later, you want std::function<void()>:
void Get(std::function<void()>, const std::string& path);
Get ([&]{ Http.registerNode(...); }, "");
note, however, that this makes lifetime of the objects refered to within the {} above quite dangerous.
I'm trying to understand the static cast as used in the Pybind11 docs here. Specifically, they use the syntax
static_cast<void (Pet::*)(int)>(&Pet::set)
Since I haven't seen this syntax before I'm strugling to interpret and apply to my own code so I was hoping somebody could explain what's going on here. Thanks
Edit - some context
I am creating Pybind11 bindings to an overloaded method that has two signatures, which only differ by const qualification. The class I am binding is a template so I am using this strategy to create the bindings
template<class T>
class Matrix {
public:
...
/**
* get the row names
*/
std::vector<std::string> &getRowNames() {
return rowNames;
}
/**
* get the row names (mutable)
*/
const std::vector<std::string> &getRowNames() {
return rowNames;
}
...
My version of the helper function described in that post is this:
template<typename T>
void declare_matrix(py::module &m, const std::string &typestr) {
using Class = ls::Matrix<T>;
const std::string &pyclass_name = typestr;
py::class_<Class>(m, pyclass_name.c_str(), py::buffer_protocol(), py::dynamic_attr())
.def(py::init<unsigned int, unsigned int>())
.def("getRowNames", static_cast<const std::vector<std::string>(ls::Matrix<T>::*)()>(&ls::Matrix<T>::getRowNames))
but the getRowNames line produces the following error:
Address of overloaded function 'getRowNames' cannot be static_cast to type 'const std::vector<std::string> (ls::Matrix<complex<double>>::*)()'
For anybody else reading this, the cast I was able to figure out thanks to the answer is:
static_cast< std::vector<std::string>& (ls::Matrix<T>::*)()>(&Class::getRowNames)
The meaning of:
static_cast<void (Pet::*)(int)>(&Pet::set)
static_cast<T_1>(T_2) means we're casting type 2 to type 1.
T_1:
(Pet::*) is a pointer to a class member of Pet (see https://stackoverflow.com/a/9939367/14344821 for a further discussion)
void (Pet::*)(int) is a pointer to a member function that takes an int parameter, returning a void
T_2
&Pet::set is the memory location of Pet::set
So basically, we're stating explicitly that we are setting the integer value.
Now we can bind the set functions to python (allowing us to set both age and name):
.def("set", static_cast<void (Pet::*)(int)>(&Pet::set), "Set the pet's age")
.def("set", static_cast<void (Pet::*)(const std::string &)>(&Pet::set), "Set the pet's name");
I have a struct defined as:
template<typename T>
struct unique_owned_item_filter: public std::unary_function<T,bool> {
unique_owned_item_filter(){}
bool operator()(const T& item)const {
return !item->shared() || item->owner() == MPI::COMM_WORLD.Get_rank();
}
typedef T item_type;
};
and I want to use this structure in a function like this
void read_nodes(std::ifstream& infile, mesh_type& mesh, const std::list<int>&my_nodes)
{
typedef typename mesh_type::node_t nd_t;
..... follows some code .....
create_double_nodes(mesh,unique_owned_item_filter<nd_t>);
}
where the function create_double_nodes is defined as
template<typename mesh_type, typename rule_type >
void create_double_nodes(mesh_type& mesh,rule_type& rule){
.... follows some code ....
}
When I pass to create_double_nodes the argument unique_owned_item_filter I insert
its dependence on the template parameter nd_t, that, in my case, is the mesh node
of type mesh_type::node_t.
When I compile the whole, I get the error expected primary-expression before ')' token at the declaration of create_double_nodes(mesh,unique_owned_item_filter<nd_t>);.
It seems to me that the template argument is right.
Can somebody help me?
The problem in the definition of the create_double_nodes disappeared, but now the problem appeared inside the body of the function itself.
template<typename mesh_type, typename rule_type >
void create_double_nodes(mesh_type& mesh, const rule_type& rule){
typename mesh_type::nd_set_t::const_iterator it_first( mesh.nodes().begin());
while(it_first!=mesh.nodes().end()){
if(rule(*it_first))
....follows code ....
it_first++
}
when i apply the rule to the const iterator it does not accept it. The compilation gives the following error:
no match for call to '(const GALES::unique_owned_item_filter, 5, GALES::base_5_dofs> >) (GALES::fem_node, 5, GALES::base_5_dofs>* const&)'
with candidates
bool GALES::unique_owned_item_filter<T>::operator()(const T&) const [with T = GALES::fem_node<GALES::geometric_node<2>, 5, GALES::base_5_dofs>]
where
GALES::fem_node<GALES::geometric_node<2>, 5, GALES::base_5_dofs>
is the complete type of node of the mesh.
I cannot understand why the rule applied to a constant iterator is not accepted. If you need more details I will try to explain it better.
Thank you very much again.
unique_owned_item_filter<nd_t> is a type, but you're using it as a function argument, where a value is required. You probably wanted to create an object of this type instead:
create_double_nodes(mesh, unique_owned_item_filter<nd_t>());
// ^^ parens here!
This will not work as-is, though, because your function template create_double_nodes takes the second parameter by non-const reference, and such cannot bind to a temporary (such as the one created in my example above).
You have two solutions: either change create_double_nodes to take its parameter by const-reference, or create a named object for the argument:
unique_owned_item_filter<nd_t> filter;
create_double_nodes(mesh, filter);
1.Make it an object:
create_double_nodes(mesh,unique_owned_item_filter<nd_t>());
^^
2.Pass by const reference or value:
void create_double_nodes(mesh_type& mesh, const rule_type& rule){
^^^^^
I did something to break the functionality in my program, but I can't figure out what. I define a typedef in a class headerfile:
typedef boost::function<void(instr_ptr, std::vector<ResultBase*>) > GenFunction;
And inside that class I have two instances:
GenFunction Gen;
GenFunction Kill
I set them as follows:
void DataFlowSolver::SetGenFunction(GenFunction &func)
{
Gen = func;
}
void DataFlowSolver::SetKillFunction(GenFunction &func)
{
Kill = func;
}
I have another function in a seperate header file:
void GenLiveVar(const instr_ptr instr, std::vector<ResultBase*> &list);
I create an instance of the DataFlowSolver class, and attempt to assign into it as follows:
blockSolver.SetGenFunction(GenLiveVar);
However, the compiler complains:
CFG.cc:617: error: no matching function for call to
'DataFlowSolver::SetGenFunction(void (&)(instr_ptr,
std::vector >&))'
DataFlowSolver.h:21: note: candidates are: void
DataFlowSolver::SetGenFunction(GenFunction&)
But it lets me do this:
GenFunction fun = GenLiveVar;
blockSolver.SetGenFunction(fun);
Anyone have an idea what might be wrong? I know this worked before, but I'm not sure how I managed to break it...
You are passing the boost::function into Set*Function by non-const reference. That prevents temporaries from being used as arguments, and the conversion from a normal function to a boost::function creates a temporary value. You will need to use a const reference for your parameter type for the code to work correctly.