LUMIERA.clone/tests/library/meta/function-signature-test.cpp

225 lines
6.7 KiB
C++

/*
FunctionSignature(Test) - metaprogramming to extract function signature type
Copyright (C) Lumiera.org
2017, 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 function-signature-test.cpp
** unit test \ref FunctionSignature_test
*/
#include "lib/test/run.hpp"
#include "lib/format-cout.hpp"
#include "lib/format-util.hpp"
#include "lib/meta/function.hpp"
#include <functional>
#include <string>
using std::function;
using std::placeholders::_1;
using std::bind;
using std::string;
using std::tuple;
using std::move;
namespace lib {
namespace meta {
namespace test {
using lib::meta::_Fun;
using lib::meta::typeStr;
namespace { // test subjects
int
freeFun (uint i)
{
return -i+1;
}
struct Functor
{
int ii = 2;
int
fun (uint i2)
{
return ii + freeFun(i2);
}
int
operator() (uint i2)
{
return 2*ii - fun(i2);
}
static int
staticFun (uint i)
{
return 2*freeFun (i);
}
};
/* ===== diagnostics helper ===== */
template<typename F>
string
showSig (F)
{
return typeStr<typename _Fun<F>::Sig>();
}
template<typename F>
string
showSigRef (F&)
{
return typeStr<typename _Fun<F>::Sig>();
}
template<typename F>
string
showSigCRef (F&)
{
return typeStr<typename _Fun<F>::Sig>();
}
template<typename F>
string
showSigRRef (F&&)
{
return typeStr<typename _Fun<F>::Sig>();
}
} // (End) test subjects
using Func = function<int(uint)>;
using FuncF = function<int(Functor&, uint)>;
/*********************************************************************//**
* @test verify metaprogramming trait to pick up function signature types.
* - ability to handle _function like_ entities uniformly
* - can handle function references, function pointers,
* member pointer to function, functor objects,
* `std::function` and lambdas
* - supports arbitrary number of arguments
* @see lib::meta::_Fun
* @see typelist.hpp
* @see FunctionClosure_test
*/
class FunctionSignature_test : public Test
{
virtual void
run (Arg)
{
// this is how the key trick of the _Fun traits template works:
// for anything "function like" we retrieve a member-pointer to the function call operator
// which we then pass on to the dedicated overload for member pointers
CHECK ("int (Functor::*)(unsigned int)" == typeStr<decltype(&Functor::operator())>());
Func f1{freeFun};
Func f2{&freeFun};
Func f3{Functor::staticFun};
Func f4{&Functor::staticFun};
Functor funk;
auto lambda = [&](uint ii) { return funk.fun(ii); };
Func f5{lambda};
CHECK ("int (unsigned int)" == showSig (freeFun));
CHECK ("int (unsigned int)" == showSig (&freeFun));
CHECK ("int (unsigned int)" == showSig (Functor::staticFun));
CHECK ("int (unsigned int)" == showSig (lambda));
CHECK ("int (unsigned int)" == showSig (f5));
CHECK ("int (unsigned int)" == showSigRef (freeFun));
CHECK ("int (unsigned int)" == showSigRef (lambda));
CHECK ("int (unsigned int)" == showSigRef (f5));
CHECK ("int (unsigned int)" == showSigCRef (freeFun));
CHECK ("int (unsigned int)" == showSigCRef (lambda));
CHECK ("int (unsigned int)" == showSigCRef (f5));
CHECK ("int (unsigned int)" == showSigRRef (move(lambda)));
CHECK ("int (unsigned int)" == showSigRRef (move(f5)));
CHECK ("int (unsigned int)" == showSig (move(&freeFun)));
CHECK ("int (unsigned int)" == showSig (move(lambda)));
CHECK ("int (unsigned int)" == showSig (move(f5)));
Func& funRef = f1;
Functor& funkyRef = funk;
Func const& funCRef = f1;
Functor const& funkyCRef = funk;
CHECK ("int (unsigned int)" == showSig (funRef));
CHECK ("int (unsigned int)" == showSig (funkyRef));
CHECK ("int (unsigned int)" == showSig (funCRef));
CHECK ("int (unsigned int)" == showSig (funkyCRef));
CHECK ("int (unsigned int)" == typeStr<_Fun<int(uint)>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Func&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Func&&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Func const&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Functor&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Functor&&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Functor const&>::Sig>());
using Siggy = _Fun<Func>::Sig;
CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy&&>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<Siggy const&>::Sig >());
auto memfunP = &Functor::fun;
FuncF fM{memfunP};
Func fMF{bind (fM, funk, _1)};
CHECK ("int (unsigned int)" == typeStr<_Fun<decltype(memfunP)>::Sig>());
CHECK ("int (Functor&, unsigned int)" == typeStr<_Fun<decltype(fM)>::Sig >());
CHECK ("int (unsigned int)" == typeStr<_Fun<decltype(fMF)>::Sig >());
}
};
/** Register this test class... */
LAUNCHER (FunctionSignature_test, "unit common");
}}} // namespace lib::meta::test