* most usages are drop-in replacements * occasionally the other convenience functions can be used * verify call-paths from core code to identify usages * ensure reseeding for all tests involving some kind of randomness... __Note__: some tests were not yet converted, since their usage of randomness is actually not thread-safe. This problem existed previously, since also `rand()` is not thread safe, albeit in most cases it is possible to ignore this problem, as ''garbled internal state'' is also somehow „random“
271 lines
8.6 KiB
C++
271 lines
8.6 KiB
C++
/*
|
|
VariadicArgumentPicker(Test) - access individual arguments from a variadic template
|
|
|
|
Copyright (C) Lumiera.org
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
* *****************************************************/
|
|
|
|
|
|
/** @file variadic-argument-picker-test.cpp
|
|
** verify metaprogramming manipulation on a variadic parameter pack.
|
|
** The unittest VariadicArgumentPicker_test calls a variadic function with different
|
|
** number of arguments and it employs variadic-helper.hpp to alter the order of passed arguments.
|
|
**
|
|
** The primary difficulty when dealing with variadic templates is the fact that a variadic
|
|
** parameter pack is not a first class type, rather a special language construct which can only
|
|
** be used to perform a pattern match. For this reason, metaprogramming has to proceed "backwards",
|
|
** by invoking a delegate template, thereby dissecting the parameter pack by a pattern match.
|
|
** The key technique for more elaborate manipulation is to construct a variadic index sequence
|
|
** as a helper, and then to expand that index sequence to drive instantiation of a helper
|
|
** template on individual arguments.
|
|
**
|
|
** @see variadic-helper.hpp
|
|
** @see path-array.hpp
|
|
** @see TypeSeqManipl_test
|
|
** @see TupleRecordInit_test
|
|
** @see TypeListManip_test
|
|
**
|
|
*/
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
#include "lib/meta/variadic-helper.hpp"
|
|
#include "lib/format-string.hpp"
|
|
#include "lib/format-cout.hpp"
|
|
#include "lib/format-util.hpp"
|
|
|
|
#include <utility>
|
|
|
|
using util::_Fmt;
|
|
using util::join;
|
|
using util::toString;
|
|
using std::forward;
|
|
using std::string;
|
|
|
|
|
|
namespace lib {
|
|
namespace meta {
|
|
namespace test {
|
|
|
|
|
|
namespace { // test data
|
|
|
|
template<int n>
|
|
struct N
|
|
{
|
|
uint i_;
|
|
static int instanceCnt;
|
|
|
|
N (uint x = rani(1 + abs(n)))
|
|
: i_{x}
|
|
{
|
|
++instanceCnt;
|
|
}
|
|
~N()
|
|
{
|
|
--instanceCnt;
|
|
}
|
|
N (N const& r)
|
|
: i_{r.i_}
|
|
{
|
|
++instanceCnt;
|
|
}
|
|
N (N&& rr)
|
|
{
|
|
std::swap (i_, rr.i_);
|
|
++instanceCnt;
|
|
}
|
|
|
|
// instanceCnt remains same...
|
|
N& operator= (N const&) = default;
|
|
N& operator= (N&&) = default;
|
|
|
|
operator string() const
|
|
{
|
|
static _Fmt format{"%s──%s─"};
|
|
return format % typeStr(*this) % i_;
|
|
}
|
|
friend bool operator== (N const& l, N const& r) { return l.i_ == r.i_; }
|
|
friend bool operator!= (N const& l, N const& r) { return l.i_ != r.i_; }
|
|
};
|
|
|
|
template<int n>
|
|
int N<n>::instanceCnt = 0;
|
|
|
|
|
|
/**
|
|
* Variadic test function to invoke
|
|
*/
|
|
template<class...ARGS>
|
|
string
|
|
fun (ARGS&& ...args)
|
|
{
|
|
static _Fmt format{"%2d╎%s┤"};
|
|
return format % sizeof...(ARGS) % join({toString(args)...}, "┼");
|
|
}
|
|
} // (End) test data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************//**
|
|
* @test check the basic utilities for manipulating variadic template arguments.
|
|
* - single out and pick an argument designated by index
|
|
* - pick an argument with fallback on default construction
|
|
* - demonstrate usage by reordering the position of arguments
|
|
*/
|
|
class VariadicArgumentPicker_test : public Test
|
|
{
|
|
virtual void
|
|
run (Arg)
|
|
{
|
|
seedRand();
|
|
verify_fixture();
|
|
check_pickArg ();
|
|
check_pickInit();
|
|
check_reorderedArguments();
|
|
|
|
CHECK (0 == N<0>::instanceCnt);
|
|
CHECK (0 == N<1>::instanceCnt);
|
|
CHECK (0 == N<2>::instanceCnt);
|
|
CHECK (0 == N<3>::instanceCnt);
|
|
}
|
|
|
|
|
|
void
|
|
verify_fixture ()
|
|
{
|
|
CHECK (0 == N<0>::instanceCnt);
|
|
CHECK (0 == N<1>::instanceCnt);
|
|
CHECK (0 == N<2>::instanceCnt);
|
|
CHECK (0 == N<3>::instanceCnt);
|
|
{
|
|
N<1> n1;
|
|
N<2> n2;
|
|
N<3> n3;
|
|
N<3> nn{n3};
|
|
cout << fun (n1,n2,n3,nn) << endl;
|
|
|
|
CHECK (0 == N<0>::instanceCnt);
|
|
CHECK (1 == N<1>::instanceCnt);
|
|
CHECK (1 == N<2>::instanceCnt);
|
|
CHECK (2 == N<3>::instanceCnt);
|
|
|
|
}
|
|
CHECK (0 == N<0>::instanceCnt);
|
|
CHECK (0 == N<1>::instanceCnt);
|
|
CHECK (0 == N<2>::instanceCnt);
|
|
CHECK (0 == N<3>::instanceCnt);
|
|
}
|
|
|
|
|
|
void
|
|
check_pickArg ()
|
|
{
|
|
N<1> n1;
|
|
N<2> n2;
|
|
N<3> n3;
|
|
|
|
CHECK (n1 == pickArg<0> (n1,n2,n3));
|
|
CHECK (n2 == pickArg<1> (n1,n2,n3));
|
|
CHECK (n3 == pickArg<2> (n1,n2,n3));
|
|
|
|
// does not compile...
|
|
// pickArg<3> (n1,n2,n3);
|
|
|
|
N<0> n0{42};
|
|
CHECK (n0 != pickArg<0> (N<0>{23}));
|
|
CHECK (n0 == pickArg<0> (N<0>{n0}));
|
|
}
|
|
|
|
|
|
void
|
|
check_pickInit ()
|
|
{
|
|
N<1> n1;
|
|
N<2> n2;
|
|
using N0 = N<0>;
|
|
|
|
CHECK (1 == (pickInit<0,int> (1,2) ));
|
|
CHECK (2 == (pickInit<1,int> (1,2) ));
|
|
CHECK (0 == (pickInit<2,int> (1,2) ));
|
|
|
|
CHECK (n1 == (pickInit<0,N0> (n1,n2) ));
|
|
CHECK (n2 == (pickInit<1,N0> (n1,n2) ));
|
|
|
|
CHECK ("N<0>" == typeStr(pickInit<3,N0> (n1,n2)));
|
|
CHECK ("N<0>" == typeStr(pickInit<3,N0> (1,"2")));
|
|
CHECK ("N<0>" == typeStr(pickInit<3,N0> ()));
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* Demonstration of argument manipulation through metaprogramming.
|
|
* This function invokes the ubiquitous `fun` test function with arbitrary arguments,
|
|
* but it re-orders and even prunes arguments as dictated by the Index sequence parameter.
|
|
* @remarks Note some fine points:
|
|
* - the value of the parameter `IndexSeq<idx...>` is irrelevant
|
|
* - rather, its sole purpose is to _pattern match_ against the type
|
|
* - we use `IndexSeq` just as an container to hold the sequence `idx...`
|
|
* - the expression within the function argument list expands the argument packs
|
|
* - and both of them are treated separately
|
|
* - the actual arguments are wrapped into a `std::forward` for _perfect forwarding_
|
|
* - but the key trick of the whole operation lies in the expansion of the `idx...` pack
|
|
* - note that `idx` without the `...` sits within the template list of `pickArg<idx>`
|
|
* - while the corresponding expansion operator is outmost and thus works on the whole expression
|
|
* - and thus it is the `idx...` pack which actually drives the generation of several `pickArg` instantiations
|
|
* - in the end the net effect is that the _Index sequence_ absolutely dictates which arguments are picked
|
|
*/
|
|
template<class...ARGS, size_t...idx>
|
|
static auto
|
|
call_with_reversed_arguments (IndexSeq<idx...>, ARGS&& ...args)
|
|
{
|
|
return fun (pickArg<idx> (forward<ARGS>(args)...) ...);
|
|
}
|
|
|
|
/** @test demonstrate reordering of arguments */
|
|
void
|
|
check_reorderedArguments ()
|
|
{
|
|
N<0> n0;
|
|
N<1> n1;
|
|
N<2> n2;
|
|
N<3> n3;
|
|
|
|
cout << fun (n0,n1,n2,n3) << endl;
|
|
|
|
using Backwards = typename BuildIndexSeq<4>::Descending; // 3,2,1,0
|
|
using Back2 = typename BuildIndexSeq<2>::Descending; // 1,0
|
|
using After2 = typename BuildIndexSeq<4>::After<2>; // 2,3
|
|
|
|
cout << call_with_reversed_arguments (Backwards(), n0,n1,n2,n3) <<endl;
|
|
cout << call_with_reversed_arguments (Back2() , n0,n1,n2,n3) <<endl;
|
|
cout << call_with_reversed_arguments (After2() , n0,n1,n2,n3) <<endl;
|
|
}
|
|
};
|
|
|
|
|
|
/** Register this test class... */
|
|
LAUNCHER (VariadicArgumentPicker_test, "unit common");
|
|
|
|
|
|
|
|
}}} // namespace lib::meta::test
|