2017-11-19 01:43:19 +01:00
|
|
|
|
/*
|
|
|
|
|
|
DuckDetectorExtension(Test) - detecting support for extension points at compile time
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2017, Hermann Vosseler <Ichthyostega@web.de>
|
2017-11-19 01:43:19 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** 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. See the file COPYING for further details.
|
2017-11-19 01:43:19 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2017-11-19 01:43:19 +01:00
|
|
|
|
|
|
|
|
|
|
/** @file duck-detector-extension-test.cpp
|
|
|
|
|
|
** unit test \ref DuckDetectorExtension_test
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
|
|
|
|
#include "lib/meta/duck-detector.hpp"
|
|
|
|
|
|
#include "lib/util.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace lib {
|
|
|
|
|
|
namespace meta{
|
|
|
|
|
|
namespace test{
|
|
|
|
|
|
|
|
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { // test types and definitions to explore....
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
fun (long)
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
|
fun (string, long)
|
|
|
|
|
|
{
|
|
|
|
|
|
return 12;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
fun ()
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Cheesy
|
2017-12-05 04:34:24 +01:00
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
double funny (char, char, string);
|
|
|
|
|
|
void funky() const;
|
|
|
|
|
|
short fuzzy (float, float);
|
2024-11-21 18:07:30 +01:00
|
|
|
|
llong fuzzy();
|
2017-12-05 04:34:24 +01:00
|
|
|
|
double fully;
|
|
|
|
|
|
};
|
2017-11-19 01:43:19 +01:00
|
|
|
|
|
|
|
|
|
|
class Fishy
|
|
|
|
|
|
{
|
2017-12-05 04:34:24 +01:00
|
|
|
|
/** @note private function can never be detected */
|
2024-11-21 18:07:30 +01:00
|
|
|
|
llong fuzzy();
|
2017-12-05 04:34:24 +01:00
|
|
|
|
|
2017-11-19 01:43:19 +01:00
|
|
|
|
/** @note type Fishy exposes an extension point `fun` */
|
|
|
|
|
|
friend void fun (Fishy&);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}//(End) test definitions
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************************//**
|
2017-12-05 04:34:24 +01:00
|
|
|
|
* @test demonstrate some details regarding detection of functions within a type.
|
|
|
|
|
|
* The purpose of these metaprogramming techniques is to write generic containers,
|
|
|
|
|
|
* handlers, iterators etc, which automatically adapt themselves to the abilities
|
|
|
|
|
|
* of their payload type. To give an example, we may investigate the argument type
|
|
|
|
|
|
* of a functor or lambda, and then compose it with a suitable adapter or converter
|
|
|
|
|
|
* to work with the given data.
|
|
|
|
|
|
*
|
|
|
|
|
|
* However, when it comes to detecting the presence of a specific function, there
|
|
|
|
|
|
* are some complexities and variations to consider. Sometimes we only want to check
|
|
|
|
|
|
* for the presence of some function, while in other cases we also want to verify
|
|
|
|
|
|
* the exact signature of that function. Moreover, some of these detection techniques
|
|
|
|
|
|
* break down whenever there is overload ambiguity; thus we might need to resort to
|
|
|
|
|
|
* an alternative, not so strict test to get past such limitations.
|
2017-11-19 01:43:19 +01:00
|
|
|
|
*/
|
|
|
|
|
|
class DuckDetectorExtension_test : public Test
|
|
|
|
|
|
{
|
2017-12-05 04:34:24 +01:00
|
|
|
|
|
2017-11-19 01:43:19 +01:00
|
|
|
|
META_DETECT_EXTENSION_POINT (funZ);
|
|
|
|
|
|
META_DETECT_EXTENSION_POINT (fun);
|
2017-12-05 04:34:24 +01:00
|
|
|
|
|
|
|
|
|
|
META_DETECT_FUNCTION (double, funny, (char, char, string));
|
2024-11-21 18:07:30 +01:00
|
|
|
|
META_DETECT_FUNCTION (llong, fuzzy, (void));
|
2017-12-05 04:34:24 +01:00
|
|
|
|
META_DETECT_FUNCTION_NAME (funny);
|
|
|
|
|
|
META_DETECT_FUNCTION_NAME (funky);
|
|
|
|
|
|
META_DETECT_FUNCTION_NAME (fuzzy);
|
|
|
|
|
|
META_DETECT_FUNCTION_NAME (fully);
|
|
|
|
|
|
META_DETECT_MEMBER(funny);
|
|
|
|
|
|
META_DETECT_MEMBER(funky);
|
|
|
|
|
|
META_DETECT_MEMBER(fuzzy);
|
|
|
|
|
|
META_DETECT_MEMBER(fully);
|
|
|
|
|
|
META_DETECT_FUNCTION_ARGLESS (funny);
|
|
|
|
|
|
META_DETECT_FUNCTION_ARGLESS (funky);
|
|
|
|
|
|
META_DETECT_FUNCTION_ARGLESS (fuzzy);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
|
run (Arg)
|
|
|
|
|
|
{
|
|
|
|
|
|
detect_freeFunctionADL_ExtensionPoint();
|
|
|
|
|
|
detect_memberFunctionVariations();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test detect the presence of a free function extension point at compile time.
|
|
|
|
|
|
* It is a common idiom in C++ to expose an extension point through a free function,
|
|
|
|
|
|
* which is expected to be picked up by ADL. To mention a prominent example, any type
|
|
|
|
|
|
* can offer the ability to be _iterated_ by injecting free functions `begin(TY)` and
|
|
|
|
|
|
* `end(TY)`, to yield a STL compatible iterator.
|
|
|
|
|
|
*
|
|
|
|
|
|
* Since such an extension point is used just by invoking the _unqualified_ function
|
|
|
|
|
|
* with the target type, we can build a meta predicate based on the fact if such an
|
|
|
|
|
|
* function invocation expression can be formed for the type in question.
|
|
|
|
|
|
*
|
|
|
|
|
|
* @note the test really hinges on the ability to form the extension point call.
|
|
|
|
|
|
* For this reason, some implicit conversions might be involved, and some
|
|
|
|
|
|
* other conversions won't work (like passing a value to an extension point
|
|
|
|
|
|
* taking a reference).
|
|
|
|
|
|
*/
|
2017-11-19 01:43:19 +01:00
|
|
|
|
void
|
2017-12-05 04:34:24 +01:00
|
|
|
|
detect_freeFunctionADL_ExtensionPoint()
|
2017-11-19 01:43:19 +01:00
|
|
|
|
{
|
|
|
|
|
|
fun ();
|
|
|
|
|
|
fun (23);
|
|
|
|
|
|
fun ("FUN", 45);
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_funZ<long>::value );
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<long> ::value );
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<long&> ::value );
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<long&&> ::value );
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<char> ::value );
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<char&> ::value );
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<char&&> ::value );
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<string> ::value );
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<void> ::value );
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<Cheesy> ::value );
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<Fishy> ::value );
|
|
|
|
|
|
CHECK ( HasExtensionPoint_fun<Fishy&> ::value );
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<Fishy&&> ::value );
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<Fishy const&>::value );
|
2017-12-05 04:34:24 +01:00
|
|
|
|
|
|
|
|
|
|
CHECK ( not HasExtensionPoint_fun<Fishy const&>::value );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test cover variations of member function detection
|
|
|
|
|
|
* - detect an explicitly given full signature
|
|
|
|
|
|
* - detect just the presence of a function _name_
|
|
|
|
|
|
* - distinguish this from detecting a _member_
|
|
|
|
|
|
* - detect especially a member function without arguments
|
|
|
|
|
|
* @note some corner cases are demonstrated here as well:
|
|
|
|
|
|
* - private functions can not be detected
|
|
|
|
|
|
* - detection fails on ambiguity due to overloads
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
|
|
|
|
|
detect_memberFunctionVariations()
|
|
|
|
|
|
{
|
|
|
|
|
|
CHECK ( HasFunSig_funny<Cheesy> ::value ); // explicit function signature detected
|
|
|
|
|
|
CHECK ( HasFunSig_funny<Cheesy const> ::value ); // const qualifier is irrelevant
|
|
|
|
|
|
CHECK ( not HasFunSig_funny<Cheesy const&> ::value ); // but reference does not work, obviously
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( HasFunSig_fuzzy<Cheesy> ::value ); // explicit function signature detected, overload is irrelevant
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( HasFunName_funny<Cheesy> ::value ); // function name detected (arguments irrelevant)
|
|
|
|
|
|
CHECK ( HasFunName_funky<Cheesy> ::value ); // detected irrespective of const modifier
|
|
|
|
|
|
CHECK ( not HasFunName_fuzzy<Cheesy> ::value ); // function name fuzzy *not* detected due to overload ambiguity
|
|
|
|
|
|
CHECK ( not HasFunName_fully<Cheesy> ::value ); // name fully is a member, not a function
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( HasMember_funny<Cheesy> ::value ); // 'funny' is not only a function, it is also a member
|
|
|
|
|
|
CHECK ( HasMember_funky<Cheesy> ::value );
|
|
|
|
|
|
CHECK ( not HasMember_fuzzy<Cheesy> ::value ); // WARNING: member 'fuzzy' *not* detected due to overload ambiguity
|
|
|
|
|
|
CHECK ( HasMember_fully<Cheesy> ::value ); // 'fully' is not a function, but it is detected as member here
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( not HasArglessFun_funny<Cheesy> ::value ); // there is no argument less function 'funny' (it takes arguments)
|
|
|
|
|
|
CHECK ( HasArglessFun_funky<Cheesy> ::value ); // but an argument-less 'funky'
|
|
|
|
|
|
CHECK ( HasArglessFun_fuzzy<Cheesy> ::value ); // and one of the 'fuzzy' overloads also takes no arguments
|
|
|
|
|
|
|
|
|
|
|
|
CHECK ( not HasFunSig_fuzzy<Fishy> ::value ); // Fishy::fuzzy() is private and can thus never be detected
|
|
|
|
|
|
CHECK ( not HasFunSig_funny<Fishy> ::value ); // and no fun with Fishy beyond that...
|
|
|
|
|
|
CHECK ( not HasFunName_funny<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasFunName_funky<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasFunName_fuzzy<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasFunName_fully<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasMember_funny<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasMember_funky<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasMember_fuzzy<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasMember_fully<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasArglessFun_funny<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasArglessFun_funky<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasArglessFun_fuzzy<Fishy> ::value );
|
|
|
|
|
|
CHECK ( not HasFunSig_fuzzy<short> ::value );
|
|
|
|
|
|
}
|
2017-11-19 01:43:19 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** Register this test class... */
|
|
|
|
|
|
LAUNCHER (DuckDetectorExtension_test, "unit meta");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}}} // namespace lib::meta::test
|