How does Q_FOREACH (= foreach) macro work and why is it that complex?
The GCC version
The GCC one is really quite simple. First of all it is used like this:
Q_FOREACH(x, cont)
{
// do stuff
}
And that will be expanded to
for (QForeachContainer<__typeof__(cont)> _container_(cont); !_container_.brk && _container_.i != _container_.e; __extension__ ({ ++_container_.brk; ++_container_.i; }))
for (x = *_container_.i;; __extension__ ({--_container_.brk; break;}))
{
// do stuff
}
So first of all:
for (QForeachContainer<__typeof__(cont)> _container_(cont); !_container_.brk && _container_.i != _container_.e; __extension__ ({ ++_container_.brk; ++_container_.i; }))
This is the actual for
loop. It sets up a QForeachContainer
to help with the iteration. The brk
variable is intitialised to 0. Then the condition is tested:
!_container_.brk && _container_.i != _container_.e
brk
is zero so !brk
is true, and presumably if the container has any elements i
(the current element) doesn't equal e
(the last element) yet.
Then the body of that outer for
is entered, which is:
for (variable = *_container_.i;; __extension__ ({--_container_.brk; break;}))
{
// do stuff
}
So x
is set to *_container_.i
which is the current element the iteration is on, and there is no condition so presumably this loop will continue forever. Then the body of the loop is entered, which is our code, and it's just a comment so it doesn't do anything.
Then the increment part of the inner loop is entered, which is interesting:
__extension__ ({--_container_.brk; break;})
It decrements brk
so that's now -1, and breaks out of the loop (with __extension__
which makes GCC not emit warnings for using GCC extensions, like you now know).
Then the increment part of the outer loop is entered:
__extension__ ({ ++_container_.brk; ++_container_.i; })
which increments brk
again and makes it 0 again, and then i
is incremented so we get to the next element. The condition is checked, and since brk
is now 0 and i
presumably doesn't equal e
yet (if we have more elements) the process is repeated.
Why did we decrement and then increment brk
like that? The reason is because the increment part of the inner loop will not be executed if we used break
in the body of our code, like this:
Q_FOREACH(x, cont)
{
break;
}
Then brk
would still be 0 when it breaks out of the inner loop, and then the increment part of the outer loop would be entered and increment it to 1, then !brk
would be false and the outer loop's condition would evaluate to false, and the foreach would stop.
The trick is to realise that there are two for
loops; the outer one's lifetime is the whole foreach, but the inner one only lasts for one element. It would be an infinite loop since it doesn't have a condition, but it is either break
ed out of by it's increment part, or by a break
in the code you provide it. That's why x
looks like it is assigned to "only once" but actually it's assigned to on every iteration of the outer loop.
The VS version
The VS version is a little more complicated because it has to work around the lack of the GCC extension __typeof__
and block-expressions, and the version of VS it was written for (6) didn't have auto
or other fancy C++11 features.
Let's look at an example expansion for what we used earlier:
if(0){}else
for (const QForeachContainerBase &_container_ = qForeachContainerNew(cont); qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->condition(); ++qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->i)
for (x = *qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->i; qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->brk; --qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->brk)
{
// stuff
}
The if(0){}else
is because VC++ 6 did the scoping of for
variables wrong and a variable declared in the initialisation part of a for
loop could be used outside the loop. So it's a workaround for a VS bug. The reason they did if(0){}else
instead of just if(0){...}
is so that you can't add an else
after the loop, like
Q_FOREACH(x, cont)
{
// do stuff
} else {
// This code is never called
}
Second, let's look at the initialisation of the outer for
:
const QForeachContainerBase &_container_ = qForeachContainerNew(cont)
The definition of QForeachContainerBase
is:
struct QForeachContainerBase {};
And the definition of qForeachContainerNew
is
template <typename T>
inline QForeachContainer<T>
qForeachContainerNew(const T& t) {
return QForeachContainer<T>(t);
}
And the definition of QForeachContainer
is
template <typename T>
class QForeachContainer : public QForeachContainerBase {
public:
inline QForeachContainer(const T& t): c(t), brk(0), i(c.begin()), e(c.end()){};
const T c;
mutable int brk;
mutable typename T::const_iterator i, e;
inline bool condition() const { return (!brk++ && i != e); }
};
So to make up for the lack of __typeof__
(which analogous to the decltype
of C++11) we have to use polymorphism. The qForeachContainerNew
function returns a QForeachContainer<T>
by value but due to lifetime extension of temporaries, if we store it in a const QForeachContainer&
, we can prolong it's lifetime till the end of the outer for
(actually the if
because of VC6's bug). We can store a QForeachContainer<T>
in a QForeachContainerBase
because the former is a subclass of the latter, and we have to make it a reference like QForeachContainerBase&
instead of a value like QForeachContainerBase
to avoid slicing.
Then for the condition of the outer for
:
qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->condition();
The definition of qForeachContainer
is
inline const QForeachContainer<T> *qForeachContainer(const QForeachContainerBase *base, const T *) {
return static_cast<const QForeachContainer<T> *>(base);
}
And the definition of qForeachPointer
is
template <typename T>
inline T *qForeachPointer(const T &) {
return 0;
}
This is where you might not be aware of what's going on since these functions seem kind of pointless. Well here's how they work and why you need them:
We have a QForeachContainer<T>
stored in a reference to a QForeachContainerBase
with no way to get it back out (that we can see). We have to cast it to the proper type somehow, and that's where the two functions come in. But how do we know what type to cast it to?
A rule of the ternary operator x ? y : z
is that y
and z
must be of the same type. We need to know the type of the container, so we use the qForeachPointer
function to do that:
qForeachPointer(cont)
The return type of qForeachPointer
is T*
, so we use template type deduction to deduce the type of the container.
The true ? 0 : qForeachPointer(cont)
is to be able to pass a NULL
pointer of the right type to qForeachContainer
so it will know what type to cast the pointer we give it to. Why do we use the ternary operator for this instead of just doing qForeachContainer(&_container_, qForeachPointer(cont))
? It's to avoid evaluating cont
many times. The second (actually third) operand to ?:
is not evaluated unless the condition is false
, and since the condition is true
itself, we can get the right type of cont
without evaluating it.
So that solves that, and we use qForeachContainer
to cast _container_
to the right type. The call is:
qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))
And again the definition is
inline const QForeachContainer<T> *qForeachContainer(const QForeachContainerBase *base, const T *) {
return static_cast<const QForeachContainer<T> *>(base);
}
The second parameter will always be NULL
because we do true ? 0
which always evaluates to 0
, and we use qForeachPointer to deduce the type T
, and use that to cast the first argument to a QForeachContainer<T>*
so we can use its member functions/variables with the condition (still in the outer for
):
qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->condition()
And condition
returns:
(!brk++ && i != e)
which is the same as the GCC version above except that it increments brk
after evaluating it. So !brk++
evaluates to true
and then brk
is incremented to 1.
Then we enter the inner for
and begin with the initialisation:
x = *qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->i
Which just sets the variable to what the iterator i
is pointing to.
Then the condition:
qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->brk
Since brk
is 1, the body of the loop is entered, which is our comment:
// stuff
Then the increment is entered:
--qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->brk
That decrements brk
back to 0. Then the condition is checked again:
qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->brk
And brk
is 0 which is false
and the loop is exited. We come to the increment part of the outer for
:
++qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->i
And that increments i
to the next element. Then we get to the condition:
qForeachContainer(&_container_, true ? 0 : qForeachPointer(cont))->condition()
Which checks that brk
is 0 (which it is) and increments it to 1 again, and the process is repeated if i != e
.
This handles break
in client code only a little differently than the GCC version, since brk
will not be decremented if we use break
in our code and it will still be 1, and the condition()
will be false for the outer loop and the outer loop will break
.
And as GManNickG stated in the comments, this macro is a lot like Boost's BOOST_FOREACH
which you can read about here.
Proper use of C++ 'for each' options
The purpose and functioning of std::for_each
is very different from that of the macros BOOST_FOREACH
and Q_FOREACH
.
std::for_each
is, first and foremost, a function call. It is an algorithm. You call it, providing a pair of iterators. On each member of the iterator range, it will call the given function with the value fetched from the iterator in question.
The purpose of std::for_each
, conceptually speaking, is really to match up with the more specific algorithms that already exist. With algorithms like count
, copy
, etc, it makes sense to have one that simply executes arbitrary code for every element.
BOOST_FOREACH
and Q_FOREACH
are equivalent constructs (which I will collectively call FOREACH
), but behave differently from std::for_each
.
FOREACH
is, first and foremost, a for loop. Now, that might not sound so different, but think about it. You cannot call continue
and break
from within std::for_each
. continue
can be emulated easily enough with return
(though this also means you can't return from the function that issues the std::for_each
call). But there's no way to escape from the std::for_each
loop if you want to stop. Similarly, you can't goto
out of a for_each
loop. The best you can do in either case is throw an exception, and that's using exceptions for flow control (ie: not a good idea).
When you use std::for_each
, you must provide some callable function. This could be a function pointer or function object. Because of that, your code is somewhat de-localized. This is fine if what you're doing in each iteration is a complex, multi-line function. But if each iteration's logic is quite simple, then code readability decreases a bit.
FOREACH
executes a local block of code. So the code is right there; you don't have to track down a function to see what's happening on each iteration.
Also, calling a function means having to write that function. If you need to keep track of state, you now need a functor, which requires more code to write.
C++11 makes std::for_each
much more attractive with lambda functions. This removes the code locality problem: the source code is right there. And since lambdas can capture stuff, it can work almost exactly like a regular for
loop. Well, except for no break
functionality, but that's usually avoidable.
Of course, C++11 also makes it effectively obsolete (along with FOREACH
) with range-based for
loops. But since there are different levels of conformance with C++11, there are some environments where you have lambda but not range-based for
.
What you ought to use is up to you. FOREACH
is nice, and if you're already using Boost and/or Qt, then feel free. But I wouldn't suddenly start using these just for FOREACH
. Personally, I wouldn't use std::for_each
unless you're also using lambdas or something, due to code locality issues. Just use a for
loop.
What does Q_D macro do in Qt
In short, Qt uses private implementation to manage data. For classes that do this, there usually is an X class and an XPrivate class. The Q_D macro defines the "d" pointer so if you write d->whatever, you have access to that private data part.
This article should pretty much cover most of your questions:
https://wiki.qt.io/D-Pointer
Why is this allocating an unneeded temporary container
It means that you create a container with this statement: m_registeredResponseObjects.keys()
for no good reason. This function iterates over your m_registeredResponseObjects, collects all keys and returns a container where you then iterator over just the get the values from m_registeredResponseObjects by key.
This makes no sense at all - why not simply
for (auto val : qAsConst(m_registeredResponseObjects))
delete val;
or even simpler with the Qt macro qDeleteAll()
qDeleteAll(m_registeredResponseObjects);
?
Expanding macro globally: is it possible to automate?
I'm not aware of any built-in way to automate this with Eclipse CDT.
You could probably write an Eclipse plugin to automate it, although if manually invoking "Explore Macro Expansion" (I assume that's what you're referring to in your question) crashes, then your plugin is likely to run into the same crash. I would suggest filing a bug about that crash either way.
You could also look into other tools like clang-expand.
Why does self-defined macro not work with argument from let?
I think this is because the
N
is defined at run-time and the macro works at compile-time?
Yes, that's correct. You can think of it this way: when Clojure evaluates a form, it first completely macroexpands the form, then it evaluates that macroexpanded result. Starting with your example:
(let [n 2] (readn n))
Since let
is a macro, Clojure expands it:
(macroexpand-1 '(let [n 2] (readn n)))
;=> (let* [n 2] (readn n))
Now let
has bottomed out to the special form let*
, and the expression for n
(2
) isn't a macro, so Clojure doesn't need to expand it.
However, the body form (readn n)
is a macro form. Remember that macros get passed their arguments unevaluated, so in this case your readn
macro literally receives the symbol n
.
(macroexpand-1 '(readn n))
;=> java.lang.ClassCastException
Macros are just functions that run at compile-time, so this...
(defmacro readn [n]
`(list ~@(repeat n '(read))))
(macroexpand-1 '(readn 2))
;=> (clojure.core/list (read) (read))
(macroexpand-1 '(readn n))
;=> java.lang.ClassCastException
... is equivalent to this:
(defn readn [n]
`(list ~@(repeat n '(read))))
(readn '2)
;=> (clojure.core/list (read) (read))
(readn 'n)
;=> java.lang.ClassCastException
My recommendation would be to just not use a macro at all here. A function would work perfectly well in this case:
(defn readn [n]
(doall (repeatedly n read)))
(let [n 2] (readn n))
Is it a good idea to apply some basic macros to simplify code in a large project?
IMHO this is generally a bad idea. You are essentially changing well known and understood syntax to something of your own invention. Before long you may find that you have re-invented the language. :)
Related Topics
How to Perform a Pairwise Binary Operation Between the Elements of Two Containers
What Is Wrong with Making a Unit Test a Friend of the Class It Is Testing
How to Use Capturestackbacktrace to Capture the Exception Stack, Not the Calling Stack
Win32 Setforegroundwindow Unreliable
Performance Degradation Due to Default Initialisation of Elements in Standard Containers
Dropping Privileges in C++ on Windows
Qt 5.5 Embed External Application into Qwidget
Access Extern Variable in C++ from Another File
C++ Cannot Convert from Base a to Derived Type B via Virtual Base A
How to Iterate Through a List of Objects in C++
Is Std::String Thead-Safe with Gcc 4.3
Search 25 000 Words Within a Text
Fatal Error C1010 - "Stdafx.H" in Visual Studio How Can This Be Corrected
C++ Unified Assignment Operator Move-Semantics
Why am I Not Provided with a Default Copy Constructor from a Volatile
Why Define Operator + or += Outside a Class, and How to Do It Properly