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<Args> -- 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.
This commit is contained in:
parent
805d83c2db
commit
5191073558
3 changed files with 46 additions and 34 deletions
|
|
@ -46,7 +46,14 @@
|
||||||
|
|
||||||
/** @file try.cpp
|
/** @file try.cpp
|
||||||
* Research how to apply a tuple to a varargs function forwarder.
|
* 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<Args> 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;
|
typedef unsigned int uint;
|
||||||
|
|
@ -73,7 +80,7 @@ using std::tuple;
|
||||||
|
|
||||||
template<typename FUN, typename...ARGS>
|
template<typename FUN, typename...ARGS>
|
||||||
void
|
void
|
||||||
forwardInvoker (FUN fun, ARGS&&... args)
|
forwardInvoker (FUN& fun, ARGS&&... args)
|
||||||
{
|
{
|
||||||
cout << "forwardInvoker...\n"
|
cout << "forwardInvoker...\n"
|
||||||
<< lib::test::showVariadicTypes(args...)
|
<< lib::test::showVariadicTypes(args...)
|
||||||
|
|
@ -81,28 +88,39 @@ forwardInvoker (FUN fun, ARGS&&... args)
|
||||||
fun (std::forward<ARGS>(args)...);
|
fun (std::forward<ARGS>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename FUN, class TUP, size_t...idx>
|
template<typename FUN, typename...ARGS>
|
||||||
|
struct Holder
|
||||||
|
{
|
||||||
|
using Tup = tuple<ARGS...>;
|
||||||
|
|
||||||
|
Tup tup;
|
||||||
|
|
||||||
|
Holder (Tup& tup)
|
||||||
|
: tup{tup}
|
||||||
|
{ }
|
||||||
|
|
||||||
|
template<size_t...idx>
|
||||||
void
|
void
|
||||||
unpack_and_forward (FUN&& fun, TUP& tup, lib::meta::IndexSeq<idx...>)
|
unpack_and_forward (FUN& fun, lib::meta::IndexSeq<idx...>)
|
||||||
{
|
{
|
||||||
cout << "unpack_and_forward...\n";
|
cout << "unpack_and_forward...\n";
|
||||||
SHOW_TYPE (TUP)
|
SHOW_TYPE (Tup)
|
||||||
|
|
||||||
forwardInvoker (std::forward<FUN>(fun), std::get<idx> (std::forward<TUP>(tup))...);
|
forwardInvoker (fun, std::get<idx> (tup)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename FUN, typename...ARGS>
|
|
||||||
void
|
void
|
||||||
applyTuple (FUN&& fun, tuple<ARGS...>& args)
|
applyTuple (FUN& fun)
|
||||||
{
|
{
|
||||||
using Tup = tuple<ARGS...>;
|
|
||||||
cout << "applyTuple...\n";
|
cout << "applyTuple...\n";
|
||||||
SHOW_TYPE (Tup)
|
SHOW_TYPE (Tup)
|
||||||
|
|
||||||
using SequenceIterator = typename lib::meta::BuildIdxIter<ARGS...>::Ascending;
|
using SequenceIterator = typename lib::meta::BuildIdxIter<ARGS...>::Ascending;
|
||||||
|
|
||||||
unpack_and_forward (std::forward<FUN>(fun), args, SequenceIterator());
|
unpack_and_forward (fun, SequenceIterator());
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -110,13 +128,15 @@ applyTuple (FUN&& fun, tuple<ARGS...>& args)
|
||||||
int
|
int
|
||||||
main (int, char**)
|
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)
|
auto fun = [](int a, int b, int c)
|
||||||
{
|
{
|
||||||
cout << a<<"+"<<b<<"+"<<c<<"="<<(a+b+c)<<endl;
|
cout << a<<"+"<<b<<"+"<<c<<"="<<(a+b+c)<<endl;
|
||||||
};
|
};
|
||||||
|
|
||||||
applyTuple (fun, tup);
|
using Hol = Holder<decltype(fun), int, int, int>;
|
||||||
|
Hol holder(tup);
|
||||||
|
holder.applyTuple (fun);
|
||||||
|
|
||||||
cout << "\n.gulp.\n";
|
cout << "\n.gulp.\n";
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -70,21 +70,6 @@ namespace lib {
|
||||||
{
|
{
|
||||||
return argStorage + VERB_TOKEN_SIZE;
|
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> (TY&)
|
|
||||||
* ////////////////////////////////////////////////////////////////////TODO verify this reasoning is sound!!
|
|
||||||
*/
|
|
||||||
template<size_t idx, typename...ARGS>
|
|
||||||
decltype(auto) constexpr
|
|
||||||
get_ref (std::tuple<ARGS...>& tuple)
|
|
||||||
{
|
|
||||||
using Elm = std::remove_reference_t<
|
|
||||||
std::tuple_element_t<idx, std::tuple<ARGS...>>>;
|
|
||||||
|
|
||||||
return static_cast<Elm&&> (std::get<idx> (tuple));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class REC, class RET>
|
template<class REC, class RET>
|
||||||
|
|
@ -126,8 +111,8 @@ namespace lib {
|
||||||
template<size_t...idx>
|
template<size_t...idx>
|
||||||
RET
|
RET
|
||||||
invokeVerb (REC& receiver, meta::IndexSeq<idx...>)
|
invokeVerb (REC& receiver, meta::IndexSeq<idx...>)
|
||||||
{
|
{ //////////////////////////////////////////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, get_ref<idx> (args_)...);
|
return verb_.applyTo (receiver, std::get<idx> (std::forward<Args>(args_))...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -150,6 +135,13 @@ namespace lib {
|
||||||
VerbPack (Handler<ARGS...> handler, Literal verbID, ARGS&&... args)
|
VerbPack (Handler<ARGS...> handler, Literal verbID, ARGS&&... args)
|
||||||
: PolyHolder(PayloadType<ARGS...>(), handler, verbID, std::forward<ARGS>(args)...)
|
: PolyHolder(PayloadType<ARGS...>(), handler, verbID, std::forward<ARGS>(args)...)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
RET
|
||||||
|
applyTo (REC& receiver)
|
||||||
|
{
|
||||||
|
VerbInvoker<REC,RET>& dispatch(*this);
|
||||||
|
return dispatch.applyTo (receiver);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,11 +161,11 @@ namespace test{
|
||||||
render_verbose (TokenSeq& tokens)
|
render_verbose (TokenSeq& tokens)
|
||||||
{
|
{
|
||||||
VerboseRenderer receiver;
|
VerboseRenderer receiver;
|
||||||
// for (Token tok : tokens)
|
for (Token tok : tokens)
|
||||||
// cout << "dispatching " << tok
|
cout << "dispatching " << tok
|
||||||
// << " -> '"
|
<< " -> '"
|
||||||
// << tok.applyTo(receiver)
|
<< tok.applyTo(receiver)
|
||||||
// << "'\n";
|
<< "'\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue