In this presentation um 00:19:00, erklärt Andrei Alexandrescu die Umsetzung seiner SCOPE_EXIT
Makro. Er schafft ein ScopeGuard
Objekt auf dem Stapel, der eine Lambda auf Zerstörung führt:Wie kann __COUNTER__ hier eine ODR-Verletzung verursachen?
#define ANONYMOUS_VARIABLE(str) \
CONCATENATE(str, __COUNTER__)
namespace detail {
enum class ScopeGuardOnExit {};
template <typename Fun>
ScopeGuard<Fun>
operator+(ScopeGuardOnExit, Fun&& fn) {
return ScopeGuard<Fun>(std::forward<Fun>(fn));
}
}
#define SCOPE_EXIT \
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
= ::detail::ScopeGuardOnExit() + [&]()
So weit, so gut bekannt (er sagt sogar in seinen Dias, dass dies ein alter Hut). Die Verwendung wie folgt aussieht:
void foo()
{
SCOPE_EXIT{ printf("foo exits"); };
}
Aber 01.04.00, behauptet Chandler Carruth, dass diese Nutzung des __COUNTER__
Makro einen „anonymen“ namen eine ODR Verletzung zu schaffen, würde verursachen, wenn sie in einer Inline-Funktion verwendet. Kann das wahr sein? Das Makro wird nur verwendet, um einen lokalen Variablennamen zu erstellen, keinen Typnamen oder etwas Ähnliches. Wie könnte dies also zu einer ODR-Verletzung führen?
Ich kam gerade zu dem gleichen Schluss, dauerte eine Weile zu erkennen, dass es um die Definition der Funktion selbst ist. Aber das macht Sinn, auch wenn es sich nur um einen variablen Namen handelt. Ich denke, man kann nur hoffen, dass dies keine Probleme verursacht ... vielleicht wäre das LINE-Makro hier eine bessere Wahl? – Horstling
Ja, es sei denn, Sie möchten mehr als eines dieser Dinge in einer Zeile deklarieren. (Oder du verarschst mit '# line'.) –