Say I analyze a code like this:
struct Foo
{
void(*setParam)(const char* name, int value);
};
I use clang LibTooling and get FieldDecl on a setParam.
I figured I can get argument types like so:
auto ft = fieldDecl->getFunctionType()->getAs<FunctionProtoType>();
for (size_t i = 0; i < fpt->getNumParams(); i++)
{
QualType paramType = fpt->getParamType(i);
....
}
But how do I get argument names? ("name" and "value" in that case) Is that even possible or I need to manually look into source (with SourceManager)?
I don't think it's possible to get the parameter names directly from the type, since they're not part of the type information.
But your task can be accomplished by one more visiting to the function pointer declaration:
class ParmVisitor
: public RecursiveASTVisitor<ParmVisitor>
{
public:
bool VisitParmVarDecl(ParmVarDecl *d) {
if (d->getFunctionScopeDepth() != 0) return true;
names.push_back(d->getName().str());
return true;
}
std::vector<std::string> names;
};
Then the calling site is:
bool VisitFieldDecl(Decl *d) {
if (!d->getFunctionType()) {
// not a function pointer
return true;
}
ParmVisitor pv;
pv.TraverseDecl(d);
auto names = std::move(pv.names);
// now you get the parameter names...
return true;
}
Pay attention to the getFunctionScopeDepth() part, it's necessary because a function parameter might be a function pointer itself, something like:
void(*setParam)(const char* name, int value, void(*evil)(int evil_name, int evil_value));
getFunctionScopeDepth() being 0 ensures that this parameter is not in a nested context.
Related
I've got several functions in a namespace. The parameters are different, for every invocation they store an object containing a string member to a vector.
There are no overloaded functions in the namespace.
I'd like to create a macro that produces a lambda expression for matching objects created via a call of a certain function. In addition to that the macro should also result in a compile time error iff a function with the name provided as parameter does not exists in the namespace. Influencing results in case of an successful compilation? (If possible at all the compilation results with and without this check would be the same without relying on code that may or may not be optimized out based on optimization level.) Is this possible? If it is possible: How can I implement this?
Example of what I'm trying to achieve; the macro I'm asking about is CALL_INFO_PREDICATE; the static_assert_function_exists part is a placeholder for any code that would achieve the desired result:
struct CallInfo
{
const std::string m_function;
CallInfo(const std::string& function)
: m_function(function)
{
}
}
std::vector<CallInfo*> g_calledFunctions;
namespace mymath
{
// all functions with same return type, but differnent parameter lists
double sin(double radian)
{
g_calledFunctions.push_back(new CallInfo("sin"));
...
}
double atan2(double y, double x)
{
g_calledFunctions.push_back(new CallInfo("atan2"));
...
}
}
#define CALL_INFO_PREDICATE(functionName) [] (CallInfo* info) -> bool\
{\
static_assert_function_exists(mymath::functionName);/* << how to make this work? */\
return info->m_function == #functionName;\
}
int main ()
{
mymath::sin(1);
mymath::atan2(3, 7);
auto pos = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), CALL_INFO_PREDICATE(sin)); // compiles; function sin exists in mymath
auto pos2 = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), CALL_INFO_PREDICATE(cos)); // produces compile time error, since there is no function named cos in mymath
...
}
Why not store the function pointers in the CallInfo and eliminate the need for macros?
struct CallInfo
{
const std::string m_function;
void* m_function_ptr;
CallInfo(const std::string& function, void* function_ptr)
: m_function(function),
m_function_ptr(function_ptr)
{
}
}
std::vector<CallInfo*> g_calledFunctions;
namespace mymath
{
// all functions with same return type, but differnent parameter lists
double sin(double radian)
{
g_calledFunctions.push_back(new CallInfo("sin", sin));
...
}
double atan2(double y, double x)
{
g_calledFunctions.push_back(new CallInfo("atan2", atan2));
...
}
}
int main ()
{
mymath::sin(1);
mymath::atan2(3, 7);
auto pos = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), [](CallInfo* info) { return info->m_function_ptr == &mymath::sin; });
auto pos2 = std::find_if(g_calledFunctions.begin(), g_calledFunctions.end(), [](CallInfo* info) { return info->m_function_ptr == &mymath::cos; });
// ...
}
Now the compiler can check for you automatically whether the function exists.
You might just use it, assuming no overloads:
#define CALL_INFO_PREDICATE(functionName) [] (CallInfo* info) -> bool \
{ \
static_cast<void>(&mymath::functionName); \
return info->m_function == #functionName; \
}
cast to void to avoid warning for unused expression.
I am getting the error term does not evaluate to a function taking 1 arguments when trying to call a function pointer.
The function pointer is stored in a struct. The struct is then stored in a map.
Definition:
typedef void (CLIOptions::*OptionHandler)(QString);
struct OptionDefinition {
QString name;
QString description;
QString type;
OptionHandler handler;
};
typedef std::map<QString, OptionDefinition> CLIOptionMap;
I initialise the map like this:
CLIOptionMap optionMap =
{
{
QString("set-tcp-host"),
{
QString("set-tcph"),
QString("Set the TCP server host address"),
QString("string"),
&CLIOptions::setTcpHost
}
},
// etc...
}
The problem occurs when I try to iterate through the map and call the handler:
for (it = optionMap.begin(); it != optionMap.end(); ++it) {
QString value = /*snip...*/
(it->second.handler)(value)
}
What is my problem here?
Your problem is that you don't have a function pointer, you have a pointer to member function, and they are very different beasts. A pointer-to-member-function isn't even a pointer in general (it has to be able to handle pointer to a virtual function in a second virtual base class!)
Given you have a pmf, you need an object to invoke the pmf on. So something like:
for (it = optionMap.begin(); it != optionMap.end(); ++it) {
QString value = /*snip...*/
const auto pmf = it->second.handler;
(mOptionHandler.*pmf)(value);
}
actually, if you going to use C++11 auto, you can also use the foreach loop:
for (const auto& option : optionMap) {
const auto pmf = option.handler;
(mOptionHandler.*pmf)(option.value);
}
So I have an overloaded templated function that needs to be passed down to a thread. I don't know how to distinguish overloaded functions to a function pointer.
template<typename T>
void DetectChange(T& variable, T& notify) { // must be a thread, else it's useless
T original = variable;
while (true) {
if (variable != original) { // change detected
notify = variable; // send notification
variable = original; // reset to original
}
}
}
template<typename T>
void DetectChange(T& variable, void (* notify)()) { // must be a thread, else it's useless (template, function pointer)
T original = variable;
while (true) {
if (variable != original) { // change detected
notify(); // do notification function
variable = original; // reset to original
}
}
}
int main() {
int x = 3;
void(*function)();
function = &DetectChange; // how to distinguish which overloaded templated function
std::thread detect = std::thread(&function, x, doSomething);
x++; // change variable
return 0;
}
Your problem is that function doesn't match either overload. function is declared taking no arguments but both available overloads take at least two. And the function-pointer type has to match down to references etc.
void (*ptr)(int &, int&) = &DetectChange;
Of course that would fail to compile because int isn't a valid T but it should give you the idea.
I wrote a special class which checks some states of some external stuff and if something changes I would like to call a callback function.
These function should be not only a global function instead of a function of a special class.
To show what I mean here is some code:
void myClass::addCallbackFunction(unsigned int key, TheSpecialClass* obj, void (TheSpecialClass::*func)(unsigned int, bool)) {
if(!obj) {
return;
}
callbackFunction cbf;
cbf.object = obj;
cbf.func = func;
if(!(callbackFunctions.find(key) == callbackFunctions.end())) {
//Key allready exists.
callbackFunctions[key].push_back(cbf);
} else {
//Key does not exists at the moment. Just create it.
vector<callbackFunction> v;
v.push_back(cbf);
callbackFunctions.insert({key, v});
}
}
void MyClass::callCallbackFunction(unsigned int key, bool newValue) {
vector<callbackFunction> cbfs;
//hasKey..
if(!(callbackFunctions.find(key) == callbackFunctions.end())) {
cbfs = callbackFunctions[key];
}
//calling every function which should be called on a state change.
for(vector<callbackFunction>::iterator it = cbfs.begin(); it != cbfs.end(); ++it) {
((it->object)->*(it->func))(key, newValue);
}
}
//to show the struct and the used map
struct callbackFunction {
TheSpecialClass* object;
void (TheSpecialClass::*func)(unsigned int, bool) ;
};
map<unsigned int, vector<callbackFunction> > callbackFunctions;
Now I want to make 'TheSpecialClass' to some kind of Pointer to a class which can variate. I found void-Pointer but then I have to know which class I passed. I thought there is something like the function pointer out there which I did not found yet.
Do someone know a solution?
I used boost::signal2 to match my usecase.
A tutorial for boost::signal2 is found here.
The signals whould only call functions. Not functions on a special object. There is a workaround by using boost::bind() like:
boost::bind(boost::mem_fn(&SpecialClass::memberFunctionOfTheClass), PointerToTheObjectOfSepcialClass, _1)
The _1 is a placeholder which creates a function (reference) which requires one argument. You can add some more placeholders to use more arguments.
Hello I have a problem with a callback function. I'm relative new to c++.
I have two classes helper and exporter:
Helper:
class Helper {
typedef Bool (*IterationCallback)(BaseObject *op);
public: Int32 RecurseHierarchy (BaseObject* op, IterationCallback callback) {
Int32 count = 0;
while (op) {
if (callback(op)) {
count++;
count += RecurseHierarchy(op->GetDown(), callback);
op = op->GetNext();
}
}
return count;
}
};
Exporter:
class Exporter {
private: Helper helper;
private: Bool writeT3D (Filename exportT3D) {
string filepath = C4DStringToStdString(exportT3D.GetString());
t3DFile.open(filepath.c_str());
writeBegin();
// Iterate all objects in the document and writes an actor
BaseDocument *doc = GetActiveDocument();
Int32 count = helper.RecurseHierarchy(doc->GetFirstObject(), this->WriteActor);
writeEnd();
t3DFile.close();
return true;
}
};
And I'm getting the errorC3867 function call missing argument list and I should use &Exporter::WriteActor. But I can't solve the problem. Can someone help me?
The problem
Assuming WriteActor to be a member function of Exporter, then its type is probably:
Bool (Exporter::*)(BaseObject*)
which is not compatible with:
Bool (*)(BaseObject*)
The reason is that in the former an implicit parameter is passed of type Exporter* (normally accessible inside the member function as this), while in the latter this does not happen.
One solution
For the above reason, you need to explicitly pass this implicit argument of type Exporter*, before passing the resulting function to RecurseHierarchy.
In your case you can use std::bind as follows:
using namespace std::placeholders;
auto fn = std::bind(&Exporter::WriterActor, this, _1);
Int32 count = helper.RecurseHierarchy(doc->GetFirstObject(), fn);
and then modify Helper to take any callable object:
struct Helper {
template<typename Fn>
Int32 RecurseHierarchy(BaseObject* op, Fn callback) {
Int32 count = 0;
while (op) {
if (callback(op)) {
count++;
count += RecurseHierarchy(op->GetDown(), callback);
op = op->GetNext();
}
}
return count;
}
};
Live demo
The above change is especially important if you also want to allow std::function objects and lambdas to be passed.