Mam następujący API:Żywotność lambda schwytany odniesień w const lambdas
old_operation(stream, format, varArgs);
I chcę napisać adaptera pozwalają napisać wezwanie następująco:
stream << operation(format, varArgs);
Aby w tym celu używam tymczasowego obiektu, który przechowuje odwołania do varArgs i przeciąża operator<<
, aby zastosować old_operation()
w następujący sposób:
template<typename ...T>
decltype(auto) storage(T&& ...t) {
return [&](auto&& f) ->decltype(auto) {
return std::forward<decltype(f)>(f)(t...);
};
}
template<typename ...T>
class Operation
{
using Storage = decltype(storage(std::declval<T>()...));
public:
template<typename ...Args>
explicit Operation(Args&& ...args) :
mArgs(storage(std::forward<Args>(args)...)) {};
template<class StreamType>
StreamType& Apply(StreamType& stream)
{
auto f = [&](auto&& ...xs)
{
old_operation(stream, std::forward<decltype(xs)>(xs)...);
}
mArgs(f);
return stream;
}
private:
Storage mArgs;
};
template<typename ...Args>
Operation<Args...> MakeOperation(Args&&... args)
{
return Operation<Args...>(std::forward<Args>(args)...);
}
template<class StreamType, typename ...Args>
StreamType& operator<<(StreamType& stream, Operation<Args...>&& operation)
{
return operation.Apply(stream);
}
Działa to świetnie, ale teraz muszę dodać kilka using namespace
deklaracji osadzone na wezwanie Operation:
powiedzmy mam
namespace X {namespace Y { namespace Z { int formater(double x) { return std::round(x); }}}
A ja nie chcę, aby dodać wszystkie przestrzenie nazw dla tego połączenia , więc robię coś takiego:
#define OPERATION(...) \
[&]() { \
using namespace ::X:Y:Z; \
return Operation("" __VA_ARGS__); }() \
która pozwala mi robić:
stream << OPERATION(format, formater(2.3));
Problem z lambda polega na tym, że tymczasniki są tworzone w innym zakresie niż wywołanie Apply()
, które jest UB.
Nie wiem, czy dodając const constifier do mArgs, przedłuży to żywotność przechwyconych referencji, jak wspomniano: here. Nie jestem pewien, czy to ma zastosowanie, zakładam, że są to referencje oparte na stosach i że dodając kwalifikator const do mArgs, kwalifikator zostanie zastosowany do przechwyconych odniesień.
Przedłużenie okresu ważności tymczasowego z "const &" dotyczy tylko lokalnych zmiennych funkcyjnych. Nie możesz przekazać tymczasowego do klasy, a następnie trzymać się go za pomocą 'const &'. – NathanOliver
Obawiałem się tego, będę nadal próbował znaleźć inne rozwiązanie niż – dlavila
Zastanawiam się, dlaczego coś tak prostego jak 'szablon Strumień & operator << (Strumień & strm, Format && f, Rest && ... vargs) { old_operation (stm, std :: forward (f), std :: forward (vargs) ...); powrót strm; } 'nie będzie działać? Po prostu pytam z ciekawości. –
Arunmu