W this presentation około 00:19:00, Andrei Alexandrescu wyjaśnia implementację swojego makra SCOPE_EXIT
. Tworzy ScopeGuard
obiekt na stosie, który wykonuje lambda na zniszczenia:W jaki sposób __COUNTER__ może spowodować naruszenie ODR?
#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() + [&]()
Tak daleko, tak dobrze znane (nawet stwierdza w swojej zjeżdżalniami, że jest to stary kapelusz). Wykorzystanie wygląda następująco:
void foo()
{
SCOPE_EXIT{ printf("foo exits"); };
}
Ale 01:04:00 Chandler Carruth twierdzi, że korzystanie z __COUNTER__
makro do stworzenia „anonimowy” nazwę spowodowałoby naruszenie zasad ODR użyte w funkcji inline. Czy to może być prawda? Makro służy tylko do tworzenia nazwy zmiennej lokalnej, a nie nazwy typu lub czegoś, więc w jaki sposób może to spowodować naruszenie ODR?
Właśnie doszedł do tego samego wniosku, zajęło mi trochę czasu, aby uświadomić sobie, że to chodzi o definicję samej funkcji. Ale ofc ma sens, nawet jeśli chodzi tylko o inną zmienną nazwę. Sądzę, że można mieć tylko nadzieję, że to nie spowoduje żadnych problemów ... może makro LINE byłoby lepszym wyborem tutaj? – Horstling
Tak, chyba że chcesz zadeklarować więcej niż jedną z tych rzeczy w jednym wierszu. (Albo mieszkasz z '# line'.) –