Skip to content
Snippets Groups Projects
Commit 7666b559 authored by Timo Koch's avatar Timo Koch Committed by Simon Praetorius
Browse files

[typetraits] Implement Dune::IsCallable

This is a type trait that checks whether some type has
a defined ()-operator that can be invoked with a given
list of arguments types and returns objects of a specified type.

Is is an improved implementation of Dune::Std::is_callable
which is deprecated.
parent ddbe19c3
Branches
Tags
1 merge request!969Cleanup/deprecate Dune::Std::is_callable is_invocable
......@@ -24,8 +24,13 @@
`Dune::Std::is_callable` and `std::is_invocable` are slightly different concepts,
since `std::is_invocable` also covers invocation of pointers to member functions
and pointers to data members. To additionally constrain for that case,
`std::is_invocable` can be used in combination with
`std::is_member_pointer_v<std::decay_t<F>>` to only allow `FunctionObject`s.
there is now `Dune::IsCallable` (in `dune/common/typetraits.hh`)
- Added `Dune::IsCallable` (in `dune/common/typetraits.hh`) which is
an improved version of the deprecated `Dune::Std::is_callable` and allows
for checking if a type is a function object type,
i.e. has a ()-operator than can be invoked with the given argument types and
returns a specified return type.
- Remove c++ feature tests in cmake for existing c++-17 standards. Add default
defines for `DUNE_HAVE_CXX_BOOL_CONSTANT`, `DUNE_HAVE_CXX_EXPERIMENTAL_BOOL_CONSTANT`,
......
......@@ -209,6 +209,10 @@ dune_add_test(SOURCES hybridutilitiestest.cc
dune_add_test(SOURCES indicestest.cc
LABELS quick)
dune_add_test(SOURCES iscallabletest.cc
LINK_LIBRARIES dunecommon
LABELS quick)
dune_add_test(SOURCES iteratorfacadetest2.cc
LABELS quick)
......
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <dune/common/typetraits.hh>
#include <dune/common/test/testsuite.hh>
int main()
{
Dune::TestSuite test;
{
auto f = [](int /*i*/) { return 0; };
using F = decltype(f);
test.check(Dune::IsCallable<F(int)>() == true)
<< "Dune::IsCallable does not accept copy from r-value";
test.check(Dune::IsCallable<F(int&)>() == true)
<< "Dune::IsCallable does not accept copy from l-value reference";
test.check(Dune::IsCallable<F(int&&)>() == true)
<< "Dune::IsCallable does not accept copy from r-value reference";
test.check(Dune::IsCallable<F(std::string)>() == false)
<< "Dune::IsCallable accepts invalid argument type";
test.check(Dune::IsCallable<F(int, int)>() == false)
<< "Dune::IsCallable accepts invalid argument count";
test.check(Dune::IsCallable<F(int), int>() == true)
<< "Dune::IsCallable does not accept valid return type";
test.check(Dune::IsCallable<F(int), std::string>() == false)
<< "Dune::IsCallable accepts invalid return type";
}
{
auto f = [](const int& /*i*/) {};
using F = decltype(f);
test.check(Dune::IsCallable<F(int)>() == true)
<< "Dune::IsCallable does not accept const& temporary from r-value";
test.check(Dune::IsCallable<F(int&)>() == true)
<< "Dune::IsCallable does not accept const& temporary from l-value reference";
test.check(Dune::IsCallable<F(int&&)>() == true)
<< "Dune::IsCallable does not accept const& temporary from r-value reference";
}
{
auto f = [](int& /*i*/) {};
using F = decltype(f);
test.check(Dune::IsCallable<F(int)>() == false)
<< "Dune::IsCallable accepts l-value reference from r-value";
test.check(Dune::IsCallable<F(int&)>() == true)
<< "Dune::IsCallable does not accept l-value reference from l-value reference";
test.check(Dune::IsCallable<F(int&&)>() == false)
<< "Dune::IsCallable accepts l-value reference from r-value reference";
}
{
auto f = [](int&& /*i*/) {};
using F = decltype(f);
test.check(Dune::IsCallable<F(int)>() == true)
<< "Dune::IsCallable does not accept r-value reference from r-value";
test.check(Dune::IsCallable<F(int&)>() == false)
<< "Dune::IsCallable accepts r-value reference from l-value reference";
test.check(Dune::IsCallable<F(int&&)>() == true)
<< "Dune::IsCallable does not accept r-value reference from r-value reference";
}
return test.exit();
}
......@@ -133,6 +133,45 @@ namespace Dune
template<typename T>
struct AlwaysTrue : public std::true_type {};
/**
* \brief Check if a type is callable with ()-operator and given arguments
* \ingroup CxxUtilities
*
* \tparam D Function descriptor
* \tparam R Return value type
*
* If `D = F(Args...)` this checks if F can be called with an
* argument list of type `Args...`, and if the return value can
* be converted to R. If R is `void`, any return type is accepted.
*
* The result is encoded by deriving from
* either `std::true_type` or `std::false_type`
*
* If D is not of the form `F(Args...)` this class is not defined.
*
* \note This differs from `std::invocable_r` in the way that only
* `FunctionObject` types are allowed here while `std::invocable_r`
* also accepts pointers to member functions and pointers
* to data members (i.e. more general `Callable` types)
* \note See https://en.cppreference.com/w/cpp/named_req/FunctionObject
* for the description of the named requirement `FunctionObject`
* and https://en.cppreference.com/w/cpp/named_req/Callable
* for `Callable`.
*/
template<typename D, typename R = void>
struct IsCallable;
/**
* \brief Check if a type is callable with ()-operator and given arguments
* \ingroup CxxUtilities
*/
template<typename R, typename F, typename... Args>
struct IsCallable<F(Args...), R>
: public std::bool_constant<
std::is_invocable_r_v<R, F, Args...>
&& !std::is_member_pointer_v<std::decay_t<F>>
> {};
//! \brief Whether this type acts as a scalar in the context of
//! (hierarchically blocked) containers
/**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment