From 519107355842e85c6be09c65ca78d7c5e0a409dc Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 20 Apr 2019 17:27:47 +0200 Subject: [PATCH] Library: continue Investigation with workaround, inconclusive yet A simple yet weird workaround (and basically equivalent to our helper function) is to wrap the argument tuple itself into std::forward -- which has the effect of exposing RValue references to the forwarding function, thus silencing the compiler. I am not happy with this result, since it contradicts the notion of perfect forwarding. As an asside, the ressearch has sorted out some secondary suspicions.. - it is *not* the Varargs argument pack as such - it is *not* the VerbToken type as such The problem clearly is related to exposing tuple elements to a forwarding function. --- research/try.cpp | 44 ++++++++++++++------ src/lib/verb-visitor.hpp | 26 ++++-------- tests/library/verb-visitor-dispatch-test.cpp | 10 ++--- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/research/try.cpp b/research/try.cpp index 45ee20e06..02fbf7a0f 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -46,7 +46,14 @@ /** @file try.cpp * Research how to apply a tuple to a varargs function forwarder. - * The recent stadard library has a std::apply, which we can not yet use, unfortunately. + * The recent standard library has a std::apply, which we can not yet use, unfortunately. + * @note this research remains inconclusive. As far as I can see, the simplified setup + * exactly mimics the problematic call situation; however, in the real use case, + * we need to std::forward the argument tuple object field while here in + * this simplified case, it compiles just fine without -- as it should after all, + * since that is the whole point of perfect forwarding; std::get should expose + * a LValue reference to the tuple element, and we pass that through a forwarding + * function into the double dispatch to the receiving visitor. */ typedef unsigned int uint; @@ -73,7 +80,7 @@ using std::tuple; template void -forwardInvoker (FUN fun, ARGS&&... args) +forwardInvoker (FUN& fun, ARGS&&... args) { cout << "forwardInvoker...\n" << lib::test::showVariadicTypes(args...) @@ -81,28 +88,39 @@ forwardInvoker (FUN fun, ARGS&&... args) fun (std::forward(args)...); } -template +template +struct Holder + { + using Tup = tuple; + + Tup tup; + + Holder (Tup& tup) + : tup{tup} + { } + +template void -unpack_and_forward (FUN&& fun, TUP& tup, lib::meta::IndexSeq) +unpack_and_forward (FUN& fun, lib::meta::IndexSeq) { cout << "unpack_and_forward...\n"; - SHOW_TYPE (TUP) + SHOW_TYPE (Tup) - forwardInvoker (std::forward(fun), std::get (std::forward(tup))...); + forwardInvoker (fun, std::get (tup)...); } -template void -applyTuple (FUN&& fun, tuple& args) +applyTuple (FUN& fun) { - using Tup = tuple; cout << "applyTuple...\n"; SHOW_TYPE (Tup) using SequenceIterator = typename lib::meta::BuildIdxIter::Ascending; - unpack_and_forward (std::forward(fun), args, SequenceIterator()); + unpack_and_forward (fun, SequenceIterator()); } + }; + @@ -110,13 +128,15 @@ applyTuple (FUN&& fun, tuple& args) int main (int, char**) { - auto tup = std::make_tuple(1,2,3u); + auto tup = std::make_tuple(1,2,3); auto fun = [](int a, int b, int c) { cout << a<<"+"<; + Hol holder(tup); + holder.applyTuple (fun); cout << "\n.gulp.\n"; return 0; diff --git a/src/lib/verb-visitor.hpp b/src/lib/verb-visitor.hpp index 58c4d7348..dee711f6f 100644 --- a/src/lib/verb-visitor.hpp +++ b/src/lib/verb-visitor.hpp @@ -70,21 +70,6 @@ namespace lib { { return argStorage + VERB_TOKEN_SIZE; } - - /** - * Helper: pass a reference to an tuple element into a "perfect forwarding" call - * This is the equivalent of calling std::forward (TY&) - * ////////////////////////////////////////////////////////////////////TODO verify this reasoning is sound!! - */ - template - decltype(auto) constexpr - get_ref (std::tuple& tuple) - { - using Elm = std::remove_reference_t< - std::tuple_element_t>>; - - return static_cast (std::get (tuple)); - } } template @@ -126,8 +111,8 @@ namespace lib { template RET invokeVerb (REC& receiver, meta::IndexSeq) - { - return verb_.applyTo (receiver, get_ref (args_)...); + { //////////////////////////////////////////TICKET #1006 | TICKET #1184 why do we need std::forward here? the target is a "perfect forwarding" function, which should be able to receive a LValue reference to the tuple element just fine... + return verb_.applyTo (receiver, std::get (std::forward(args_))...); } }; @@ -150,6 +135,13 @@ namespace lib { VerbPack (Handler handler, Literal verbID, ARGS&&... args) : PolyHolder(PayloadType(), handler, verbID, std::forward(args)...) { } + + RET + applyTo (REC& receiver) + { + VerbInvoker& dispatch(*this); + return dispatch.applyTo (receiver); + } }; diff --git a/tests/library/verb-visitor-dispatch-test.cpp b/tests/library/verb-visitor-dispatch-test.cpp index 343d142d2..2c8dfca1d 100644 --- a/tests/library/verb-visitor-dispatch-test.cpp +++ b/tests/library/verb-visitor-dispatch-test.cpp @@ -161,11 +161,11 @@ namespace test{ render_verbose (TokenSeq& tokens) { VerboseRenderer receiver; -// for (Token tok : tokens) -// cout << "dispatching " << tok -// << " -> '" -// << tok.applyTo(receiver) -// << "'\n"; + for (Token tok : tokens) + cout << "dispatching " << tok + << " -> '" + << tok.applyTo(receiver) + << "'\n"; } };