[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.
main
Adriaan de Groot 4 years ago
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 );
};

@ -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…
Cancel
Save