Test if calling f(x) is possible using metaprogramming - c++

The Stroustrup's book provides an example how to answer the question: "is it possible to call f(x) if x is of type X" (the section 28.4.4 "Further examples with Enable_if"). I've tried to reproduce the example but got something wrong and can't understand what.
In my code below, there is a function f(int). I expect that then the result of has_f<int>::value is 1 (true). The actual result is 0 (false).
#include <type_traits>
#include <iostream>
//
// Meta if/then/else specialization
//
struct substitution_failure { };
template<typename T>
struct substitution_succeeded : std::true_type { };
template<>
struct substitution_succeeded<substitution_failure> : std::false_type { };
//
// sfinae to derive the specialization
//
template<typename T>
struct get_f_result {
private:
template<typename X>
static auto check(X const& x) -> decltype(f(x));
static substitution_failure check(...);
public:
using type = decltype(check(std::declval<T>()));
};
//
// has_f uses the derived specialization
//
template<typename T>
struct has_f : substitution_succeeded<typename get_f_result<T>::type> { };
//
// We will check if this function call be called,
// once with "char*" and once with "int".
//
int f(int i) {
std::cout << i;
return i;
}
int main() {
auto b1{has_f<char*>::value};
std::cout << "test(char*) gives: " << b1 << std::endl;
std::cout << "Just to make sure we can call f(int): ";
f(777);
std::cout << std::endl;
auto b2{has_f<int>::value};
std::cout << "test(int) gives: " << b2 << std::endl;
}
The output:
test(char*) gives: 0
Just to make sure we can call f(int): 777
test(int) gives: 0

The main problem is that you're making an unqualified call to f here:
template<typename X>
static auto check(X const& x) -> decltype(f(x));
The fs that will be found will be those in scope at the point of definition of check() (none) and those that are found by argument-dependent lookup in the associated namespaces of X. Since X is int, it has no associated namespaces, and you find no fs there either. Since ADL will never work for int, your function has to be visible before get_f_result is defined. Just moving it up solves that problem.
Now, your has_f is overly complicated. There is no reason for the substitution_succeeded machinery. Just have the two check() overloads return the type you want:
template<typename T>
struct has_f {
private:
template <typename X>
static auto check(X const& x)
-> decltype(f(x), std::true_type{});
static std::false_type check(...);
public:
using type = decltype(check(std::declval<T>()));
};
And now has_f<T>::type is already either true_type or false_type.
Of course, even this is overly complicated. Checking if an expression is valid is a fairly common operation, so it'd be helpful to simplify it (borrowed from Yakk, similar to std::is_detected):
namespace impl {
template <template <class...> class, class, class... >
struct can_apply : std::false_type { };
template <template <class...> class Z, class... Ts>
struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...> : std::true_type { };
};
template <template <class... > class Z, class... Ts>
using can_apply = impl::can_apply<Z, void, Ts...>;
This let's you write:
template <class T>
using result_of_f = decltype(f(std::declval<T>()));
template <class T>
using has_f = can_apply<result_of_f, T>;

I can see 2 ways to fix the issue you are seeing:
Forward declare your function f. This is required because you are explicitly calling the function by name in the template get_f_result.
int f(int);
template<typename T>
struct get_f_result {
private:
template<typename X>
static auto check(X const& x) -> decltype(f(x));
static substitution_failure check(...);
public:
using type = decltype(check(std::declval<T>()));
};
The second solution is to make it more generic i.e not just for f(c) but for all function which takes an int:
//
// sfinae to derive the specialization
//
template <typename Func, Func f, typename T>
struct get_f_result {
private:
template <typename X>
static auto check(X const& x) -> decltype(f(x));
static substitution_failure check(...);
public:
using type = decltype(check(std::declval<T>()));
};
And Call it like:
template <typename T>
struct has_f : substitution_succeeded <typename get_f_result::type> { };
Again here f needs to be known here..but, you can again make it more generic by shifting the responsibility of providing the function at the caller site.

Related

SFINAE for types that don't have particular members

Why doesn't the following code compile and what is the most concise solution for enabling templates for types with particular members? Also it compiles if template variable is replaced with an expression, which is used to initialize it, directly.
#include <iostream>
template<class T>
constexpr bool is_rect = std::is_same_v<decltype(T::left, T::top, T::right, T::bottom, void()), void>;
// compiles if is_rect<T> is replaced with the expression directly, but of course it's not a solution
template<class T, std::enable_if_t<is_rect<T>, int> = 0>
void f(T)
{
std::cout << "rect enabled\n";
}
template<class T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
void f(T)
{
std::cout << "arithmetic enabled\n";
}
struct ActualType { float left, top, right, bottom; };
int main()
{
f(ActualType{});
f(int{});
return 0;
}
The problem is that is_rect<T> is always specified as template argument for std::enable_if_t as part of the signature of f(), and it's invalid expression when T doesn't have particular members.
You can apply partial specialization to make is_rect gives true or false based on the type has particular members or not. e.g.
template<class T, class = void>
constexpr bool is_rect = false;
template<class T>
constexpr bool is_rect<T, std::void_t<decltype(T::left, T::top, T::right, T::bottom)>> = true;
then
template<class T, std::enable_if_t<is_rect<T>, int> = 0>
void f(T)
{
std::cout << "rect enabled\n";
}
LIVE
The problem with your is_rect<T> is that if T is missing any of the data members, then the definition is an ill-formed expression, rather than a well-formed expression that evaluates to false.
You can use the is_detected idiom to instead test whether your template is well-formed:
Try it on godbolt.org: Demo
#include <type_traits>
namespace detail
{
template<class AlwaysVoid, template <class...> class Op, class... Args>
struct detector : std::false_type {};
template<template <class...> class Op, class... Args>
struct detector<std::void_t<Op<Args...>>, Op, Args...> : std::true_type {};
} // namespace detail
template<template <class...> class Op, class... Args>
constexpr bool is_detected_v = detail::detector<void, Op, Args...>::value;
namespace detail
{
template<class T>
using rect_detector = decltype(T::left, T::top, T::right, T::bottom);
} // namespace detail
template<class T>
constexpr bool is_rect = is_detected_v<detail::rect_detector, T>;
In C++20, concepts are the most concise way for enabling templates for types with particular members:
Try it on godbolt.org: Demo
#include <iostream>
#include <type_traits>
template<class T>
concept arithmetic = std::is_arithmetic_v<T>;
template<class T>
concept rect = requires (T t)
{
{ t.left };
{ t.top };
{ t.right };
{ t.bottom };
};
template<rect T>
void f(T)
{
std::cout << "rect enabled\n";
}
template<arithmetic T>
void f(T)
{
std::cout << "arithmetic enabled\n";
}

Detect if a specific C++ type has a member, EXCLUDING inherited members

I would like to detect if a particular type has a member: directly and not as a result of inheritance.
The purpose is to determine if a specific type 'has a trait' such as the ability to serialize. Naturally, and for extending the example, a sub-type might not have the ability to serialize even if the parent type does.
Is there (and if so) a "standard" solution to this request?
Is there a flaw (excluding the limitations it imposes) with the non-convertible pointer approach presented at the bottom?
When using is_member_function_pointer or other detection mechanisms, inheritance is in play. Note that the output is "1" even though B does not define the member.
#include <type_traits>
#include <iostream>
struct A {
void member() { }
};
struct B : A {
};
int main()
{
std::cout << "B has member? "
<< std::is_member_function_pointer<decltype(&B::member)>::value
<< std::endl;
}
The closest I have been able to achieve is when using a non-convertible pointer (B** has no implicit conversion to A**), although such is a bit awkward to work with. It also imposes the additional argument matched to the type and prevents any direct inheritance.
#include <type_traits>
#include <iostream>
struct A {
// would match std::declval<B*> as B* -> A*,
// hence forcing failure through B** -> A**.
// void member(A*) { }
void member(A**) { }
};
struct B : A {
// succeeds compilation aka "found" if not commented
// void member(B**) { }
};
int main()
{
// This actually fails to compile, which is OKAY because it
// WORKS when used with SFINAE during the actual detection.
// This is just a simple example to run.
// error: invalid conversion from 'B**' to 'A**'
std::cout << "B has member? "
<< std::is_member_function_pointer<
decltype(std::declval<B>().member(std::declval<B**>()))
>::value
<< std::endl;
}
There's a neat trick that can help with that.
The type of &B::member is actually void (A::*)(), not void (B::*)() (if member is inherited).
Use SFINAE to check that &B::member exists and has a proper type:
template <typename T, typename = void>
struct has_member : std::false_type {};
template <typename T> struct has_member
<T, std::enable_if_t<std::is_same_v<void (T::*)(), decltype(&T::member)>>>
: std::true_type
{};
This only works for one specific member type (member has to be void member()). Generalizing it for any type is left as an exercise to the reader.
Or you can get fancy and use the fact that void (B::*)() is for some reason not implicitly convertible to void (A::*)() specifically when passing a template parameter:
template <typename T, T>
struct detect_member_helper {};
template <typename T>
using detect_member = detect_member_helper<void (T::*)(), &T::member>;
template <typename T>
inline constexpr bool has_member = std::experimental::is_detected_v<detect_member, T>;
This might work for you:
#include <type_traits>
#include <iostream>
struct A {
void member(A**)
{}
};
struct B : A
{};
template <typename, typename = void>
struct hasMember : std::false_type {};
template <typename T>
struct hasMember<T, std::void_t<decltype(std::declval<T*>()->member())>>
: std::is_same<decltype(std::declval<T*>()->member()), void>
{};
int main() {
std::cout << "B has member ? "
<< hasMember<B>::value
<< std::endl;
}
And the output is going to be B has member ? 0.
Check it out live
Using the fact that &B::member is void (A::*)(), you might do
template <typename C, typename Sig>
struct classMember : std::false_type{};
template <typename C, typename Ret, typename ... Ts>
struct classMember<C, Ret (C::*)(Ts...)> : std::true_type{};
// and other specialization for cv and ref and c ellipsis
template <typename, typename = void>
struct hasMember : std::false_type {};
template <typename T>
struct hasMember<T, std::enable_if_t<classMember<T, decltype(&T::member)>::value>> : std::true_type
{};
Demo

C++ detect if type has template parameter

I would like to unify an interface to work with both templated and non-templated types. Is there a way to determine whether a type, such as a class or a function pointer is depends on a template parameter?
For example:
struct foo {};
template<typename T> struct bar {};
// This works if the template parameter is provided
template<typename> struct is_templated : false_type {};
template<template<typename...> class Obj, typename...Args>
struct is_templated<Obj<Args...>> : true_type {};
template<typename T> constexpr auto is_templated_v = is_templated<T>::value;
In this case, is_template_v<foo> is false and is_template_v<bar<int>> is true, but I can't just deduce anything with is_template_v<bar>. Alternatively, if I define
template<template<typename...> class>
struct temp_check : true_type {};
Then temp_check<bar> is perfectly valid, but I don't know how I would analogously check foo. What is needed is something like this if it were valid C++
template<template<> class A> struct temp_check<A> : false_type {};
Is there some mechanism that could check both?
I'd use the power of overload sets:
#include <iostream>
#include <type_traits>
struct foo {};
template<typename T> struct bar {};
template<template<class ...> class T, class... TArgs>
constexpr bool is_template() { return true; }
template<class T>
constexpr bool is_template() { return false; }
int main()
{
std::cout << is_template<foo>() << '\n'; // 0
std::cout << is_template<bar>() << '\n'; // 1
}
Let to the user: use the template function to provide a trait ;)

SFINAE not happening with std::underlying_type

Below SFINAE code with variadic templates compiles nicely using clang 3.7.1, C++14:
#include <array>
#include <iostream>
#include <vector>
#include <cstdint>
enum class Bar : uint8_t {
ay, bee, see
};
struct S {
static void foo() {}
// std::begin(h) is defined for h of type H
template<typename H, typename... T>
static typename std::enable_if<std::is_pointer<decltype(std::begin(std::declval<H>()))*>::value>::type
foo(const H&, T&&... t)
{ std::cout << "container\n"; foo(std::forward<T>(t)...); }
// H is integral
template<typename H, typename... T>
static typename std::enable_if<std::is_integral<typename std::remove_reference<H>::type>::value>::type
foo(const H&, T&&... t)
{ std::cout << "integer\n"; foo(std::forward<T>(t)...); }
// H is an enum with underlying type = uint8_t
/*
template<typename H, typename... T>
static typename std::enable_if<std::is_same<typename std::underlying_type<H>::type,uint8_t>::value>::type
foo(const H&, T&&... t)
{ std::cout << "enum\n"; foo(std::forward<T>(t)...); }
*/
};
int main()
{
S::foo(std::array<int,8>(), 5, 5L, std::vector<int>{}, 5L);
}
I want the correct overload of foo to be called recursively, based on the type H:
if std::begin(h) is defined for an h of type H, I want the
overload number 1 to be chosen
if H is an "integral type", I want overload number 2.
This works as it is. But if I add another overload for enum types (you can try to un-comment the third overload), then I get:
error: only enumeration types have underlying types
I agree that only enums got an underlying type, hence why is Not the third overload (with std::underlying_type) get SFINAE-d away?
std::underlying_type is not SFINAE friendly. Attempting to access std::underlying_type<T>::type for a non-enumeration type results in undefined behavior (often a hard error), not substitution failure.
You need to ascertain that the type at issue is an enumeration type first, before attempting to access its underlying type. Writing this in line would be something along the lines of typename std::enable_if<std::is_enum<H>::value, std::underlying_type<H>>::type::type. Replacing the typename std::underlying_type<H>::type in your return type with this hideous mess and you get an even more hideous mess that works :)
If you find yourself needing to do this often - or just don't want to write typename std::enable_if<std::is_same<typename std::enable_if<std::is_enum<H>::value, std::underlying_type<H>>::type::type, uint8_t>::value>::type - you can write a SFINAE-friendly underlying_type:
template<class T, bool = std::is_enum<T>::value>
struct safe_underlying_type : std::underlying_type<T> {};
template<class T>
struct safe_underlying_type<T, false /* is_enum */> {};
Here's a solution inspired from T.C.'s solution that worked for my use case:
template <typename T, bool = std::is_enum<T>::value>
struct relaxed_underlying_type {
using type = typename std::underlying_type<T>::type;
};
template <typename T>
struct relaxed_underlying_type<T, false> {
using type = T;
};
Example Usage:
template <typename T>
struct UnwrapEnum {
using type =
typename std::conditional<
std::is_enum<T>::value,
typename relaxed_underlying_type<T>::type,
T>
::type;
};
enum class MyEnum : int {};
class MyClass {};
int main() {
UnwrapEnum<MyEnum>::type x;
static_assert(std::is_same<decltype(x), int>::value);
UnwrapEnum<MyClass>::type y;
static_assert(std::is_same<decltype(y), MyClass>::value);
return 0;
}

Howto check a type for the existence of parameterless operator()

I'm trying to check whether a functor is compatible with a given set of parametertypes and a given return type (that is, the given parametertypes can be implicitely converted to the actual parametertypes and the other way around for the return type). Currently I use the following code for this:
template<typename T, typename R, template<typename U, typename V> class Comparer>
struct check_type
{ enum {value = Comparer<T, R>::value}; };
template<typename T, typename Return, typename... Args>
struct is_functor_compatible
{
struct base: public T
{
using T::operator();
std::false_type operator()(...)const;
};
enum {value = check_type<decltype(std::declval<base>()(std::declval<Args>()...)), Return, std::is_convertible>::value};
};
check_type<T, V, Comparer>
This works quite nicely in the majority of cases, however it fails to compile when I'm testing parameterless functors like struct foo{ int operator()() const;};, beccause in that case the two operator() of base are apperently ambigous, leading to something like this:
error: call of '(is_functor_compatible<foo, void>::base) ()' is ambiguous
note: candidates are:
note: std::false_type is_functor_compatible<T, Return, Args>::base::operator()(...) const [with T = foo, Return = void, Args = {}, std::false_type = std::integral_constant<bool, false>]
note: int foo::operator()() const
So obvoiusly I need a different way to check this for parameterless functors. I tried making a partial specialization of is_functor_compatible for an empty parameterpack, where I check if the type of &T::operator() is a parameterless memberfunction, which works more or less. However this approach obviously fails when the tested functor has several operator().
Therefore my question is if there is a better way to test for the existence of a parameterless operator() and how to do it.
When I want to test if a given expression is valid for a type, I use a structure similar to this one:
template <typename T>
struct is_callable_without_parameters {
private:
template <typename T1>
static decltype(std::declval<T1>()(), void(), 0) test(int);
template <typename>
static void test(...);
public:
enum { value = !std::is_void<decltype(test<T>(0))>::value };
};
Have you tried something like:
template<size_t>
class Discrim
{
};
template<typename T>
std::true_type hasFunctionCallOper( T*, Discrim<sizeof(T()())>* );
template<typename T>
std::false_type hasFunctionCallOper( T*, ... );
After, you discriminate on the return type of
hasFunctionCallOper((T*)0, 0).
EDITED (thanks to the suggestion of R. Martinho Fernandes):
Here's the code that works:
template<size_t n>
class CallOpDiscrim {};
template<typename T>
TrueType hasCallOp( T*, CallOpDiscrim< sizeof( (*((T const*)0))(), 1 ) > const* );
template<typename T>
FalseType hasCallOp( T* ... );
template<typename T, bool hasCallOp>
class TestImpl;
template<typename T>
class TestImpl<T, false>
{
public:
void doTellIt() { std::cout << typeid(T).name() << " does not have operator()" << std::endl; }
};
template<typename T>
class TestImpl<T, true>
{
public:
void doTellIt() { std::cout << typeid(T).name() << " has operator()" << std::endl; }
};
template<typename T>
class Test : private TestImpl<T, sizeof(hasCallOp<T>(0, 0)) == sizeof(TrueType)>
{
public:
void tellIt() { this->doTellIt(); }
};