2007-08-17 00:36:07 +02:00
/* try.cpp - for trying out some language features....
* scons will create the binary bin / try
*
2014-08-16 02:04:29 +02:00
*/
2007-08-17 00:36:07 +02:00
// 8/07 - how to control NOBUG??
2007-08-31 14:57:49 +02:00
// execute with NOBUG_LOG='ttt:TRACE' bin/try
2008-01-04 01:44:40 +01:00
// 1/08 - working out a static initialisation problem for Visitor (Tag creation)
2008-01-27 03:58:24 +01:00
// 1/08 - check 64bit longs
2008-04-05 05:57:54 +02:00
// 4/08 - comparison operators on shared_ptr<Asset>
2008-04-26 05:38:19 +02:00
// 4/08 - conversions on the value_type used for boost::any
2008-05-17 04:34:46 +02:00
// 5/08 - how to guard a downcasting access, so it is compiled in only if the involved types are convertible
2017-12-01 22:47:21 +01:00
// 7/08 - combining partial specialisation and subclasses
2008-10-26 03:21:33 +01:00
// 10/8 - abusing the STL containers to hold noncopyable values
2009-06-26 05:27:54 +02:00
// 6/09 - investigating how to build a mixin template providing an operator bool()
2009-12-31 01:21:45 +01:00
// 12/9 - tracking down a strange "warning: type qualifiers ignored on function return type"
2010-01-02 06:26:56 +01:00
// 1/10 - can we determine at compile time the presence of a certain function (for duck-typing)?
2010-04-09 07:44:31 +02:00
// 4/10 - pretty printing STL containers with python enabled GDB?
2011-01-08 03:30:10 +01:00
// 1/11 - exploring numeric limits
2011-01-20 13:21:14 +01:00
// 1/11 - integer floor and wrap operation(s)
2011-01-31 05:35:43 +01:00
// 1/11 - how to fetch the path of the own executable -- at least under Linux?
2011-10-09 14:52:58 +02:00
// 10/11 - simple demo using a pointer and a struct
2011-11-01 03:11:43 +01:00
// 11/11 - using the boost random number generator(s)
2011-12-30 03:45:10 +01:00
// 12/11 - how to detect if string conversion is possible?
2012-01-07 03:28:12 +01:00
// 1/12 - is partial application of member functions possible?
2014-05-09 00:49:15 +02:00
// 5/14 - c++11 transition: detect empty function object
2014-08-13 03:08:00 +02:00
// 7/14 - c++11 transition: std hash function vs. boost hash
2014-09-21 02:54:54 +02:00
// 9/14 - variadic templates and perfect forwarding
2014-11-22 03:31:59 +01:00
// 11/14 - pointer to member functions and name mangling
2015-08-12 02:31:41 +02:00
// 8/15 - Segfault when loading into GDB (on Debian/Jessie 64bit
2015-08-29 17:09:03 +02:00
// 8/15 - generalising the Variant::Visitor
2016-01-04 02:58:58 +01:00
// 1/16 - generic to-string conversion for ostream
2016-01-23 11:57:19 +01:00
// 1/16 - build tuple from runtime-typed variant container
2017-03-18 23:31:10 +01:00
// 3/17 - generic function signature traits, including support for Lambdas
2017-09-26 19:23:03 +02:00
// 9/17 - manipulate variadic templates to treat varargs in several chunks
2017-11-19 00:07:47 +01:00
// 11/17 - metaprogramming to detect the presence of extension points
2017-11-23 17:49:43 +01:00
// 11/17 - detect generic lambda
2017-12-01 22:47:21 +01:00
// 12/17 - investigate SFINAE failure. Reason was indirect use while in template instantiation
2018-03-11 03:20:21 +01:00
// 03/18 - Dependency Injection / Singleton initialisation / double checked locking
2018-05-01 16:59:15 +02:00
// 04/18 - investigate construction of static template members
2018-08-16 21:40:10 +02:00
// 08/18 - Segfault when compiling some regular expressions for EventLog search
2018-10-12 23:42:56 +02:00
// 10/18 - investigate insidious reinterpret cast
2018-12-31 09:05:45 +01:00
// 12/18 - investigate the trinomial random number algorithm from the C standard lib
2019-04-19 18:37:30 +02:00
// 04/19 - forwarding tuple element(s) to function invocation
2012-01-07 03:28:12 +01:00
/** @file try.cpp
2019-04-19 18:37:30 +02:00
* Research how to apply a tuple to a varargs function forwarder .
2019-04-20 17:27:47 +02:00
* 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 .
2012-01-07 03:28:12 +01:00
*/
2015-08-29 17:09:03 +02:00
typedef unsigned int uint ;
2016-01-06 04:36:53 +01:00
# include "lib/format-cout.hpp"
2018-03-17 03:36:58 +01:00
# include "lib/test/test-helper.hpp"
2018-08-16 21:40:10 +02:00
# include "lib/util.hpp"
2019-05-09 17:10:35 +02:00
# include "lib/verb-visitor.hpp"
2018-08-16 21:40:10 +02:00
2019-04-19 18:37:30 +02:00
# include "lib/meta/variadic-helper.hpp"
# include <utility>
2018-08-16 21:40:10 +02:00
# include <string>
2019-04-19 18:37:30 +02:00
# include <tuple>
2018-08-16 21:40:10 +02:00
2019-05-09 17:10:35 +02:00
using lib : : Literal ;
2018-08-16 21:40:10 +02:00
using std : : string ;
2019-04-19 18:37:30 +02:00
using std : : tuple ;
2016-01-15 23:42:49 +01:00
2017-03-19 00:19:07 +01:00
2018-03-23 23:42:10 +01:00
2016-01-15 22:51:17 +01:00
# define SHOW_TYPE(_TY_) \
cout < < " typeof( " < < STRINGIFY ( _TY_ ) < < " )= " < < lib : : meta : : typeStr < _TY_ > ( ) < < endl ;
2017-11-19 00:35:10 +01:00
# define SHOW_EXPR(_XX_) \
cout < < " Probe " < < STRINGIFY ( _XX_ ) < < " ? = " < < _XX_ < < endl ;
2016-01-05 03:32:24 +01:00
2019-04-19 18:37:30 +02:00
template < typename FUN , typename . . . ARGS >
void
2019-04-20 17:27:47 +02:00
forwardInvoker ( FUN & fun , ARGS & & . . . args )
2018-12-31 09:05:45 +01:00
{
2019-04-19 18:37:30 +02:00
cout < < " forwardInvoker... \n "
< < lib : : test : : showVariadicTypes ( args . . . )
< < endl ;
fun ( std : : forward < ARGS > ( args ) . . . ) ;
}
2019-04-20 17:27:47 +02:00
template < typename FUN , typename . . . ARGS >
struct Holder
{
2019-05-09 17:10:35 +02:00
using Args = tuple < ARGS . . . > ;
2019-04-20 17:27:47 +02:00
2019-05-09 17:10:35 +02:00
Args tup ;
2019-04-20 17:27:47 +02:00
2019-05-09 17:10:35 +02:00
Holder ( Args & tup )
2019-04-20 17:27:47 +02:00
: tup { tup }
{ }
template < size_t . . . idx >
2019-04-19 18:37:30 +02:00
void
2019-04-20 17:27:47 +02:00
unpack_and_forward ( FUN & fun , lib : : meta : : IndexSeq < idx . . . > )
2018-12-31 09:05:45 +01:00
{
2019-04-19 18:37:30 +02:00
cout < < " unpack_and_forward... \n " ;
2019-05-09 17:10:35 +02:00
SHOW_TYPE ( Args )
2019-04-19 18:37:30 +02:00
2019-04-20 17:27:47 +02:00
forwardInvoker ( fun , std : : get < idx > ( tup ) . . . ) ;
2019-04-19 18:37:30 +02:00
}
2018-12-31 09:05:45 +01:00
2019-04-19 18:37:30 +02:00
void
2019-04-20 17:27:47 +02:00
applyTuple ( FUN & fun )
2019-04-19 18:37:30 +02:00
{
cout < < " applyTuple... \n " ;
2019-05-09 17:10:35 +02:00
SHOW_TYPE ( Args )
2019-04-19 18:37:30 +02:00
using SequenceIterator = typename lib : : meta : : BuildIdxIter < ARGS . . . > : : Ascending ;
2019-04-20 17:27:47 +02:00
unpack_and_forward ( fun , SequenceIterator ( ) ) ;
2018-12-31 09:05:45 +01:00
}
2019-04-20 17:27:47 +02:00
} ;
2018-03-24 07:48:59 +01:00
2019-04-19 18:37:30 +02:00
2019-04-22 17:45:38 +02:00
///////////////////////////TODO : Debugging
struct Trackr
{
size_t num ;
Trackr ( size_t val )
: num ( val )
{
cout < < " Trackr( " < < val < < " ) " < < endl ;
}
~ Trackr ( )
{
2019-05-09 17:10:35 +02:00
cout < < " ~Trackr( " < < num < < " ) " < < endl ;
2019-04-22 17:45:38 +02:00
}
Trackr ( Trackr const & lval )
: num ( lval . num )
{
cout < < " Trackr()<<-LVal " < < endl ;
}
Trackr ( Trackr & & rval )
: num ( rval . num )
{
cout < < " Trackr()<<-RVal " < < endl ;
}
Trackr &
operator = ( Trackr const & orig )
{
cout < < " Tracker = orig " < < endl ;
num = orig . num ;
return * this ;
}
} ;
///////////////////////////TODO : Debugging
2019-04-19 18:37:30 +02:00
2019-05-09 17:10:35 +02:00
struct Receiver
{
void
grrrn ( uint & x , Trackr y )
{
cout < < " grrrn()... " < < x < < " *Trckr( " < < y . num < < " )= " < < ( x * y . num ) < < endl ;
}
} ;
template < class REC , class SIG >
struct Hodler ;
template < class REC , class RET , typename . . . ARGS >
struct Hodler < REC , RET ( ARGS . . . ) >
{
typedef RET ( REC : : * Handler ) ( ARGS . . . ) ;
Handler handler_ ;
using Verb = lib : : VerbToken < REC , RET ( ARGS . . . ) > ;
using Args = std : : tuple < ARGS . . . > ;
/** meta-sequence to pick argument values from the storage tuple */
using SequenceIterator = typename lib : : meta : : BuildIdxIter < ARGS . . . > : : Ascending ;
Verb verb_ ;
Args args_ ;
// Hodler (typename Verb::Handler handlerRef, Literal verbID, ARGS&&... args)
Hodler ( Handler handlerRef , Literal verbID , ARGS & & . . . args )
: handler_ { handlerRef }
, verb_ { handlerRef , verbID }
, args_ { std : : forward < ARGS > ( args ) . . . }
{ }
RET
applyTo ( REC & receiver )
{
return invokeVerb ( receiver , SequenceIterator ( ) ) ;
}
template < size_t . . . idx >
RET
invokeVerb ( REC & receiver , lib : : 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...
// lib::test::TypeDebugger<Args> buggy;
// return verb_.applyTo (receiver, std::get<idx> (std::forward<Args>(args_))...); /// <<------------this compiles, but consumes the tuple's content (move init)
// return verb_.applyTo (receiver, std::get<idx> (args_)...);
// return (receiver.*handler_)(std::get<idx> (args_)...); /// <<------------this works
// return applyToVerb (receiver, std::get<idx> (args_)...);
// return getVerbFun(receiver) (std::get<idx> (args_)...); /// <<------------this compiles, but creates a spurious copy
return verb_ . applyTo ( receiver , forwardElm < idx > ( args_ ) . . . ) ; /// <<------------this compiles, but consumes the tuple's content (move init)
}
template < size_t idx >
using TupleElmType = typename std : : tuple_element < idx , Args > : : type ;
template < size_t idx >
// std::remove_reference_t<decltype(std::get<idx> (args))>&&
TupleElmType < idx > & &
forwardElm ( Args & args )
{
using ElmRef = decltype ( std : : get < idx > ( args ) ) ;
using Elm = std : : remove_reference_t < TupleElmType < idx > > ;
return std : : forward < TupleElmType < idx > > ( std : : get < idx > ( args ) ) ;
}
RET
applyToVerb ( REC & receiver , ARGS & & . . . args )
{
// REQUIRE ("NIL" != token_);
return ( receiver . * handler_ ) ( std : : forward < ARGS > ( args ) . . . ) ;
}
// std::function<RET(ARGS...)>
decltype ( auto )
getVerbFun ( REC & receiver )
{
return [ & ] ( ARGS . . . args ) - > RET
{
return ( receiver . * handler_ ) ( std : : forward < ARGS > ( args ) . . . ) ;
} ;
}
} ;
2019-04-19 18:37:30 +02:00
2016-01-05 03:32:24 +01:00
int
main ( int , char * * )
{
2019-04-20 17:27:47 +02:00
auto tup = std : : make_tuple ( 1 , 2 , 3 ) ;
2019-04-19 18:37:30 +02:00
auto fun = [ ] ( int a , int b , int c )
{
cout < < a < < " + " < < b < < " + " < < c < < " = " < < ( a + b + c ) < < endl ;
} ;
2018-03-23 23:42:10 +01:00
2019-04-20 17:27:47 +02:00
using Hol = Holder < decltype ( fun ) , int , int , int > ;
Hol holder ( tup ) ;
holder . applyTuple ( fun ) ;
2018-03-19 00:44:26 +01:00
2019-04-22 17:45:38 +02:00
2019-05-09 17:10:35 +02:00
uint zwo { 2 } ;
std : : tuple < uint & , Trackr > trp { zwo , Trackr ( 3 ) } ;
2019-04-22 17:45:38 +02:00
auto frn = [ ] ( uint & x , Trackr y )
{
cout < < x < < " *Trckr( " < < y . num < < " )= " < < ( x * y . num ) < < endl ;
} ;
2019-05-09 17:10:35 +02:00
using Hrl = Holder < decltype ( frn ) , uint & , Trackr > ;
2019-04-22 17:45:38 +02:00
Hrl hrlder ( trp ) ;
hrlder . applyTuple ( frn ) ;
2019-05-09 17:10:35 +02:00
cout < < " \n .ulps. \n " ;
2019-04-22 17:45:38 +02:00
2019-05-09 17:10:35 +02:00
Hodler < Receiver , void ( uint & , Trackr ) > holyh ( & Receiver : : grrrn , " holyhandgrenade " , zwo , Trackr ( 5 ) ) ;
Receiver recy ;
// recy.grrrn (std::get<0>(trp), Trackr(5));
holyh . applyTo ( recy ) ;
2019-04-22 17:45:38 +02:00
2018-03-30 23:55:42 +02:00
cout < < " \n .gulp. \n " ;
2007-08-17 00:36:07 +02:00
return 0 ;
}