I need to mix C++ and Objective-c(++) files. I've stack in the next problem:
I have the code:
connect(menu_action,&QAction::triggered, [=]()
{
//do_smthing();
});
But when I am trying to compile file that contains this code (.mm file) I've got "excepted expression" error.
excepted expression and the compiler point to symbol = after symbol [.
How can I rebuild this code into Objective-c?
Your syntax is bad. This should read: connect(menu_action, &QAction::triggered, [=]{do_smthing();});
Note the end parenthesis before the closing semicolon.
It's worth saying that if you are just calling a function in your lambda you should prefer function pointers to lambdas. This will preserve Qt's maintenance of the signals and slots and you'll be able to call sender() in your slot.
Related
Is there a way in C++ to design a function / add some "attributes" to it in such a way that calling it several times in the code would raise a compile time error?
To give a bit of background / motivation: I was programming on Mbed-OS and I did a couple of mistakes that look like:
rtos::Thread thread;
[lots of code]
thread.start(persistent_function_1);
[lots of code in a setup function]
thread.start(persistent_function_2);
This had the (logical) consequence that the persistent_function_1, which should have been allowed to execute for the lifetime of the program, only got to execute until the thread was re-purposed to run persistent_function_2. It took me a long time to find this bug, and I was wondering if I can do something to my thread.start function to make sure I get a compiler error if I make this sort of mistake again.
I don't think there is a way to coerce the C++ language directly to detect double invocation of start() at compile time (put differently, I don't think #user4581301's suggestion would work): to statically assert a property you'd need to somehow change the entity. I'm sure you could write a custom checker using clang but I guess that isn't what you are after. It would, obviously, be possible to have a run-time assertion which reports that an already start()ed thread is started again. Again, that doesn't seem to be what you are after.
The "obvious" solution is no to have "[lots of code]" in a function to start with. In fact, std::thread entirely side-steps that issue by enforcing that there is no code between the object declaration and its start: the std::thread is started upon construction. The setup with "[lots of code]" between the object declaration and the start would be something like
my::thread thread([&]{
[lots of code]
return persistent_function_1;
}());
The caveat is that you'd need to set up your various variables sort of out of order. That is, the preferred approach would be to declare the thread object at the site where it is actually started:
[lots of code]
my::thread thread(persistent_function_1);
In both of these cases my::thread would be a trivial wrapper around rtos::thread which doesn't expose a separate start() method. As I don't know why rtos::thread separates construction and start() and a plausible reason could be the ability to set up various thread parameters, it may be reasonable to actually use two separate arguments to my::thread's constructor:
A function taking a my::thread::properties entity as parameter which allows the necessary manipulations of the thread object.
The function to be started.
That is, something like
my::thread thread([](my::thread::properties& properties) {
[lots of code manipulating the properties]
},
persistent_function_1);
This way, it remains possible to manipulate the thread but you can't possible start() a thread twice.
One option is to wrap the thread in a new manager object, with the rough shape of
class thread_manager {
rtos::Thread thread;
const std::function<...> execution_function;
/* .
.
. */
public:
thread_manager(rtos::Thread _thread, std::function<...> function, ...)
: thread { _thread }
, execution_function { function }
, ...
void start();
}
and disallowing any other usage of threading (which can be justified on the basis of encapsulation, although as pointed out in comments, yahoos are always a risk).
There is no current mechanism for detecting an expression that appears twice. But you can torture the compiler to get something close
namespace
{
template<int>
struct once
{
once() {}
friend void redefine() {}
};
}
#define ONCE(expr) (once<__COUNTER__>{}, (expr))
If ONCE ever appear twice in the same TU, the compiler will complain about redefining redefine.
ONCE(thread.start(persistent_function_1)); // ok
ONCE(thread.start(persistent_function_2)); // error
This question already has answers here:
Listing Unused Symbols
(2 answers)
Closed 7 years ago.
How do I detect function definitions which are never getting called and delete them from the file and then save it?
Suppose I have only 1 CPP file as of now, which has a main() function and many other function definitions (function definition can also be inside main() ). If I were to write a program to parse this CPP file and check whether a function is getting called or not and delete if it is not getting called then what is(are) the way(s) to do it?
There are few ways that come to mind:
I would find out line numbers of beginning and end of main(). I can do it by maintaining a stack of opening and closing braces { and }.
Anything after main would be function definition. Then I can parse for function definitions. To do this I can parse it the following way:
< string >< open paren >< comma separated string(s) for arguments >< closing paren >
Once I have all the names of such functions as described in (2), I can make a map with its names as key and value as a bool, indicating whether a function is getting called once or not.
Finally parse the file once again to check for any calls for functions with their name as in this map. The function call can be from within main or from some other function. The value for the key (i.e. the function name) could be flagged according to whether a function is getting called or not.
I feel I have complicated my logic and it could be done in a smarter way. With the above logic it would be hard to find all the corner cases (there would be many). Also, there could be function pointers to make parsing logic difficult. If that's not enough, the function pointers could be typedefed too.
How do I go about designing my program? Are a map (to maintain filenames) and stack (to maintain braces) the right data structures or is there anything else more suitable to deal with it?
Note: I am not looking for any tool to do this. Nor do I want to use any library (if it exists to make things easy).
I think you should not try to build a C++ parser from scratch, becuse of other said in comments that is really hard. IMHO, you'd better start from CLang libraries, than can do the low-level parsing for you and work directly with the abstract syntax tree.
You could even use crange as an example of how to use them to produce a cross reference table.
Alternatively, you could directly use GNU global, because its gtags command directly generates definition and reference databases that you have to analyse.
IMHO those two ways would be simpler than creating a C++ parser from scratch.
The simplest approach for doing it yourself I can think of is:
Write a minimal parser that can identify functions. It just needs to detect the start and ending line of a function.
Programmatically comment out the first function, save to a temp file.
Try to compile the file by invoking the complier.
Check if there are compile errors, if yes, the function is called, if not, it is unused.
Continue with the next function.
This is a comment, rather than an answer, but I post it here because it's too long for a comment space.
There are lots of issues you should consider. First of all, you should not assume that main() is a first function in a source file.
Even if it is, there should be some functions header declarations before the main() so that the compiler can recognize their invocation in main.
Next, function's opening and closing brace needn't be in separate lines, they also needn't be the only characters in their lines. Generally, almost whole C++ code can be put in a single line!
Furthermore, functions can differ with parameters' types while having the same name (overloading), so you can't recognize which function is called if you don't parse the whole code down to the parameters' types. And even more: you will have to perform type lists matching with standard convertions/casts, possibly considering inline constructors calls. Of course you should not forget default parameters. Google for resolving overloaded function call, for example see an outline here
Additionally, there may be chains of unused functions. For example if a() calls b() and b() calls c() and d(), but a() itself is not called, then the whole four is unused, even though there exist 'calls' to b(), c() and d().
There is also a possibility that functions are called through a pointer, in which case you may be unable to find a call. Example:
int (*testfun)(int) = whattotest ? TestFun1 : TestFun2; // no call
int testResult = testfun(paramToTest); // unknown function called
Finally the code can be pretty obfuscated with #defineās.
Conclusion: you'll probably have to write your own C++ compiler (except the machine code generator) to achieve your goal.
This is a very rough idea and I doubt it's very efficient but maybe it can help you get started. First traverse the file once, picking out any function names (I'm not entirely sure how you would do this). But once you have those names, traverse the file again, looking for the function name anywhere in the file, inside main and other functions too. If you find more than 1 instance it means that the function is being called and should be kept.
What is the easiest way to add an immediate one-time task to a CFRunLoop from a C/C++ program, that is, a callback which must be invoked by the run-loop before it blocks again.
According to the documentation, we have CFRunLoopPerformBlock(), but the problem with it, is that it uses the block-notation which requires Objective-C compilation mode.
Is there something similar to CFRunLoopPerformBlock() which is available to a C/C++ program, or am I forced to use a zero-delay timer?
The block language feature does not require the use of Objective-C. It's also supported in C and C++ by Clang. So, you can go ahead and use CFRunLoopPerformBlock().
If you're still looking for alternatives and you wish to target the main thread's run loop (i.e. the main run loop), you can use dispatch_async_f(). Although it's most common to use the block-based functions when using GCD, the functions with the _f suffix take function pointers.
static void my_task_function(void *context)
{
// ...
}
...
dispatch_async_f(dispatch_get_main_queue(), any_pointer_you_like, my_task_function);
For a Qt5/c++11 project, I'm using a QMediaPlayer object (named audio_player) with its positionChanged() signal:
This piece of code is ok:
connect(this->audio_player,
SIGNAL(positionChanged(qint64)),
this,
SLOT(audio_position_changed(qint64)));
But this one doesn't work:
typedef PosInAudio qint64;
connect(this->audio_player,
SIGNAL(positionChanged(PosInAudio)),
this,
SLOT(audio_position_changed(PosInAudio)));
At run-time I get the message "QObject::connect: No such signal QMediaPlayer::positionChanged(PosInAudio)"
I was baffled to see that even a type defined with #define wasn't ok:
#define PosInAudio qint64
connect(this->audio_player,
SIGNAL(positionChanged(PosInAudio)),
this,
SLOT(audio_position_changed(PosInAudio)));
(same error message as above)
Is this the expected behavior ? Or do I make a mistake?
As explained above (thank you Matteo Italia), everything's ok if you use the Qt5 new signal-slot syntax described here.
The problem arises from the fact that the old-style connect actually works comparing strings to match the signal and the slot, and here the signature used in the signal declaration (void positionChanged(qint64)) and the one used in your connect call (void positionChanged(PosInAudio)) don't match if you are just comparing strings.
The SIGNAL and SLOT are essentially stringifying macros (the actual signature of the old-style connect involves const char * or equivalent stuff); connect performs a normalization on the received strings (removing unnecessary spaces, const references & co. - see QMetaObject::normalizedSignature - but again, with no knowledge of typedefs or namespaces) and tries to match them to the signals/slots lists found in the metaobject.
This list, in turn, is generated by the MOC, which has quite a vague understanding of C++ syntax and semantics, and extracts the signal and slots signatures quite brutally; so, neither the strings produced by MOC nor what is put into the SIGNAL and SLOT macros are aware of subtleties like typedefs or "equivalent" names (e.g. a type local to the current namespace, which, when referenced outside, needs to have its name prepended by a namespace), so the connect will fail if you have "complicated" (and non-literally matching) type names in your signal and slots.
The new-style (Qt5+) connect (mentioned in the comments by #peppe) should solve these issues (and permit neat stuff like connecting a signal to a lambda), but if you have to live with old-style connects to avoid problems you should always refer to types in the same way - e.g., if you use a typedef in your signal declaration, you have to use it in slots too; if you have namespaced types in the signal, prefix them with the adequate namespaces and do the same in the slots.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Undefined reference to vtable. Trying to compile a Qt project
here is the code
#include <iostream>
#include <QApplication>
#include <QTimer>
class myClass : public QObject {
Q_OBJECT
public:
QTimer *timer;
myClass(){
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(mySlot()));
timer->start(1000);
}
public slots:
void mySlot() {
std::cout << "Fire" << std::endl;
}
};
int main() {
std::cout << "Hello, world";
myClass atimer;
return 0;
}
Apart from the error, there are two more things I don't understand:
Why there isn't any semicolon after macros, in this case Q_OBJECT. It doesn't seem to obey C++ syntax but yet people write code like that.
The "public slots" is a modifier created by Qt, but how come gcc compiler can still understand it. How could an IDE like Qt modify the standard syntax of a language?
You didn't give the exact error message, but I suspect what's happening is that you didn't run moc on your code, or you didn't compile the code generated by moc, or you didn't link the code into your executable/library.
As for your other questions:
You don't need to have a semicolon after macros; the preprocessor doesn't care about semicolons - only the compiler does. So whether or not you need to add a semicolon manually depends on what your macro (Q_OBJECT) in this case expands to, and where you use it. In your case, no semicolon is needed.
slots is an macro which expands to an emtpy string, so any C++ compile can process it. However, slots is also recognized as a special key word by moc. The same goes for signals, by the way (it's a macro expanding to protected:).
This is just because you didn't run qmake since you aded Q_OBJECT. Just run qmake (if you use QtCreator, it must be in the Build Menu) and then compile ;).
Hope it helped
Usually an undefined reference to vtable indicates that you declared some virtual functions, but never provide the definition to them. Perhaps Q_OBJECT is declaring something?
Macros are expanded before C++ syntax is considered, working in textual form. That is why macros themselves do not have to obey C++ syntax. If, for example, Q_OBJECT contains a semicolon at the end of its definition, so that after the substitution you get a correct C++ code, then that is good enough.
slots may be a macro as well (maybe even an empty one). Then, after substituting slots with nothingness you get a valid C++ code again.
You have to use the Meta Object Compiler delivered by QT
In general if you're getting an undefined reference to vtable error it's because qmake hasn't ran and generated a necessary moc for it. Rerunning qmake in the project directory should fix it, if it doesn't then clean the build and run quake and make again.