[libcalamares] Some if-method-exists trickery
This builds some machinery so that we can create a detector for member-functions (methods) named <whatever>. Use the macro to build the machinery: DECLARE_HAS_METHOD(myFunction) then after that, has_myFunction<T> is either std::true_type or std::false_type depending on whether T has a method myFunction.
This commit is contained in:
parent
7b6ff8dd37
commit
b5c0158ec2
@ -27,6 +27,7 @@
|
||||
#include "Entropy.h"
|
||||
#include "Logger.h"
|
||||
#include "RAII.h"
|
||||
#include "Traits.h"
|
||||
#include "UMask.h"
|
||||
#include "Yaml.h"
|
||||
|
||||
@ -313,3 +314,55 @@ LibCalamaresTests::testBoolSetter()
|
||||
}
|
||||
QVERIFY( b );
|
||||
}
|
||||
|
||||
/* Demonstration of Traits support for has-a-method or not.
|
||||
*
|
||||
* We have two classes, c1 and c2; one has a method do_the_thing() and the
|
||||
* other does not. A third class, Thinginator, has a method thingify(),
|
||||
* which should call do_the_thing() of its argument if it exists.
|
||||
*/
|
||||
|
||||
struct c1 { int do_the_thing() { return 2; } };
|
||||
struct c2 { };
|
||||
|
||||
DECLARE_HAS_METHOD(do_the_thing)
|
||||
|
||||
struct Thinginator
|
||||
{
|
||||
public:
|
||||
/// When class T has function do_the_thing()
|
||||
template< class T > int thingify( T& t, const std::true_type& )
|
||||
{
|
||||
return t.do_the_thing();
|
||||
}
|
||||
|
||||
template< class T > int thingify( T&, const std::false_type& )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
template< class T > int thingify( T& t )
|
||||
{
|
||||
return thingify(t, has_do_the_thing<T>{});
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
void
|
||||
LibCalamaresTests::testTraits()
|
||||
{
|
||||
has_do_the_thing<c1> x{};
|
||||
has_do_the_thing<c2> y{};
|
||||
|
||||
QVERIFY(x);
|
||||
QVERIFY(!y);
|
||||
|
||||
c1 c1{};
|
||||
c2 c2{};
|
||||
|
||||
QCOMPARE(c1.do_the_thing(), 2);
|
||||
|
||||
Thinginator t;
|
||||
QCOMPARE(t.thingify(c1), 2); // Calls c1::do_the_thing()
|
||||
QCOMPARE(t.thingify(c2), -1);
|
||||
}
|
||||
|
@ -53,6 +53,9 @@ private Q_SLOTS:
|
||||
/** @brief Tests the RAII bits. */
|
||||
void testBoolSetter();
|
||||
|
||||
/** @brief Tests the Traits bits. */
|
||||
void testTraits();
|
||||
|
||||
private:
|
||||
void recursiveCompareMap( const QVariantMap& a, const QVariantMap& b, int depth );
|
||||
};
|
||||
|
77
src/libcalamares/utils/Traits.h
Normal file
77
src/libcalamares/utils/Traits.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
*
|
||||
* Calamares 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calamares 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 Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
* License-Filename: LICENSE
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UTILS_TRAITS_H
|
||||
#define UTILS_TRAITS_H
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
|
||||
namespace CalamaresUtils
|
||||
{
|
||||
|
||||
/** @brief Traits machinery lives in this namespace
|
||||
*
|
||||
* The primary purpose of this namespace is to hold machinery that
|
||||
* is created by the DECLARE_HAS_METHOD macro.
|
||||
*
|
||||
* The DECLARE_HAS_METHOD macro builds machinery to check whether
|
||||
* a class has a particular named method. This can be used to
|
||||
* specialize templates elsewhere for use with classes with, or without,
|
||||
* the named method.
|
||||
*
|
||||
* To use the machinery (which is not that sophisticated):
|
||||
*
|
||||
* - Put `DECLARE_HAS_METHOD(myFunction)` somewhere in file scope.
|
||||
* This puts together the machinery for detecting if `myFunction`
|
||||
* is a method of some class.
|
||||
* - At global scope, `has_myFunction<T>` is now either std::true_type,
|
||||
* if the type `T` has a method `T::myFunction`, or std::false_type,
|
||||
* if it does not.
|
||||
*
|
||||
* To specialize template methods based on the presence of the named
|
||||
* method, write **three** overloads:
|
||||
*
|
||||
* - `template<class T> myMethod(args ..., const std::true_type& )`
|
||||
* This is the implementation where class T has `myFunction`.
|
||||
* - `template<class T> myMethod(args ..., const std::false_type& )`
|
||||
* This is the implementation without.
|
||||
* - `template<class T> myMethod(args ...)` is the general implementation,
|
||||
* which can call the specialized implementations with
|
||||
* `return myMethod(args ..., has_myFunction<T>{})`
|
||||
*/
|
||||
namespace Traits
|
||||
{
|
||||
template< class > struct sfinae_true : std::true_type{};
|
||||
}
|
||||
}
|
||||
|
||||
#define DECLARE_HAS_METHOD(m) \
|
||||
namespace CalamaresUtils { namespace Traits { \
|
||||
struct has_ ## m { \
|
||||
template< class T > static auto f(int) -> sfinae_true<decltype(&T:: m)>; \
|
||||
template< class T > static auto f(long) -> std::false_type; \
|
||||
template< class T > using t = decltype( f <T>(0) ); \
|
||||
}; } } \
|
||||
template< class T > using has_ ## m = CalamaresUtils::Traits:: has_ ## m ::t<T>;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user