Testing if member function exists using variadics - c++

So I'm very familiar with the paradigm of testing if a member function exists. Currently this code works:
#include <iostream>
#include <type_traits>
struct has_mem_func_foo_impl {
template <typename U, U>
struct chk { };
template <typename Class, typename Arg>
static std::true_type has_foo(chk<void(Class::*)(Arg), &Class::foo>*);
template <typename, typename>
static std::false_type has_foo(...);
};
template <typename Class, typename Arg>
struct has_mem_func_foo : decltype(has_mem_func_foo_impl::template has_foo<Class,Arg>(nullptr)) { };
struct bar {
void foo(int) { }
};
int main() {
static_assert( has_mem_func_foo<bar, int>::value, "bar has foo(int)" );
}
unfortunately if I make a slight adjustment:
#include <iostream>
#include <type_traits>
struct has_mem_func_foo_impl {
template <typename U, U>
struct chk { };
template <typename Class, typename... Arg>
static std::true_type has_foo(chk<void(Class::*)(Arg...), &Class::foo>*);
template <typename, typename...>
static std::false_type has_foo(...);
};
template <typename Class, typename... Arg>
struct has_mem_func_foo : decltype(has_mem_func_foo_impl::template has_foo<Class,Arg...>(nullptr)) { };
struct bar {
void foo(int) { }
};
int main() {
static_assert( has_mem_func_foo<bar, int>::value, "bar has foo(int)" );
}
my static assertion fails. I was under the impression that variadic template parameter packs are treated just the same when expanded into their places. Both gcc and clang produce a failed static assertion.
The real root of my question is thus, is this standard behavior? It also fails when testing for the presence of a variadic templated member function.

The problem I see is that Arg... being passed int is not enough. It would be valid for the compiler to add new args to the end of it.
Deducing what to add to the end of it from nullptr_t isn't possible, so the compiler says "I give up, not this case".
But we don't need to have Arg... in a deducable context for your trick to work:
#include <iostream>
#include <type_traits>
template<class Sig>
struct has_mem_func_foo_impl;
template<class R, class...Args>
struct has_mem_func_foo_impl<R(Args...)> {
template <typename U, U>
struct chk { };
template <typename Class>
static constexpr std::true_type has_foo(chk<R(Class::*)(Args...), &Class::foo>*) { return {}; }
template <typename>
static constexpr std::false_type has_foo(...) { return {}; }
};
template <typename Class, typename Sig>
struct has_mem_func_foo :
decltype(has_mem_func_foo_impl<Sig>::template has_foo<Class>(nullptr))
{};
struct bar {
void foo(int) { }
};
int main() {
static_assert( has_mem_func_foo<bar, void(int)>::value, "bar has foo(int)" );
}
we move the Args... to the class itself, then only pass in the type to the function. This blocks deduction, which makes nullptr conversion to the member function pointer doable, and things work again.
I also included some improved signature based syntax, which also means it supports return type matching.
Note that you may be asking the wrong question. You are asking if there is a member function with a particular signature: often what you want to know is if there is a member function that is invokable with a certain set of arguments, with a return type compatible with your return value.
namespace details {
template<class T, class Sig, class=void>
struct has_foo:std::false_type{};
template<class T, class R, class... Args>
struct has_foo<T, R(Args...),
typename std::enable_if<
std::is_convertible<
decltype(std::declval<T>().foo(std::declval<Args>()...)),
R
>::value
|| std::is_same<R, void>::value // all return types are compatible with void
// and, due to SFINAE, we can invoke T.foo(Args...) (otherwise previous clause fails)
>::type
>:std::true_type{};
}
template<class T, class Sig>
using has_foo = std::integral_constant<bool, details::has_foo<T, Sig>::value>;
which tries to invoke T.foo(int), and checks if the return value is compatible.
For fun, I made the type of has_foo actually be true_type or false_type, not inherited-from. I could just have:
template<class T, class Sig>
using has_foo = details::has_foo<T, Sig>;
if I didn't want that extra feature.

Related

Other ways of checking if a class has a certain member function

Let's check if
struct Thing {
int foo(double, bool) {return 0;}
};
has the int foo(double, bool) member function during compile time. There are many ways of doing this, and most are just variations of others. Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here? I'm just trying to learn some new techniques with templates and SFINAE.
#include <iostream>
#include <type_traits>
// Using void_t (this includes using std::is_detected).
template <typename T>
using void_t = void;
template <typename T, typename = void>
struct has_foo : std::false_type {};
template <typename T>
struct has_foo<T,
void_t<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>
> : std::true_type {};
// Using the ... default argument.
template <typename T>
struct hasfoo {
template <typename U>
static std::true_type test (decltype(static_cast<int(T::*)(double, bool)>(&T::foo))*); // or 'decltype(static_cast<int>(std::declval<U>().foo(double{}, bool{})))*' works fine too.
template <typename>
static std::false_type test (...);
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
// Overloads and trailing return types.
template <typename>
struct Helper : std::true_type {};
template <typename T>
auto helper(int) -> Helper<decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})))>;
template <typename>
std::false_type helper(long);
template <typename T>
constexpr bool hasFoo() {return decltype(helper<T>(0))::value;}
// Comma operator (basically the same as the above).
template <typename T>
auto check(int) -> decltype(static_cast<int>(std::declval<T>().foo(double{}, bool{})), std::true_type{});
template <typename T>
std::false_type check(...);
template <typename T>
using HasFoo = decltype(check<T>(0));
// Member function pointer template parameter.
template <typename T>
struct Hasfoo {
template <typename U, int(U::*)(double, bool)>
struct Tag;
template <typename U>
static constexpr bool test (Tag<U, &U::foo>*) {return true;}
template <typename>
static constexpr bool test (...) {return false;}
static constexpr bool value = test<T>(nullptr);
};
// Tests
struct Thing {
int foo(double, bool) {return 0;}
};
int main() {
static_assert (has_foo<Thing>::value, "");
static_assert (hasfoo<Thing>::value, "");
static_assert (hasFoo<Thing>(), "");
static_assert (HasFoo<Thing>::value, "");
}
Edit: I just remembered an elegant and more general solution that Yakk gave to a different question quite a while ago (here is his actual typing, modified only to match the foo function):
namespace meta {
namespace details {
template<template<class...>class Z, class=void, class...Ts>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply<Z, decltype((void)(std::declval<Z<Ts...>>())), Ts...>:
std::true_type
{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;
}
template<class T>
using member_foo = decltype(static_cast<int(T::*)(double, bool)>(&T::foo));
template<class T>
using has_member_foo = meta::can_apply<member_foo, T>;
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It is based on the noexcept operator and a trivial using declaration (here named Type).
SFINAE and partial template specialization do the rest.
It follows a minimal, working example:
#include<type_traits>
#include<utility>
template<typename T, bool>
using Type = T;
template<typename T, typename = T>
struct U: std::false_type {};
template<typename T>
struct U<T, Type<T, noexcept(std::declval<T>().f(42))>>: std::true_type {};
struct S { void f(int) {} };
struct T {};
int main() {
static_assert(U<S>::value, "!");
static_assert(not U<T>::value, "!");
}
This solution has a problem if compared to the others.
As an example, the struct below would pass the test as well:
struct R { int f(double) {} };
In other terms, as long as the function to be tested accepts one argument to the type of which 42 can be cast and no matter what's the return type, it is accepted.
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It is based on the sizeof operator and a trivial using declaration (here named Type).
SFINAE and partial template specialization do the rest.
It follows a minimal, working example:
#include<type_traits>
#include<cstddef>
template<typename T, std::size_t>
using Type = T;
template<typename T, typename = T>
struct U: std::false_type {};
template<typename T>
struct U<T, Type<T, sizeof(static_cast<void(T::*)(int)>(&T::f))>>: std::true_type {};
struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};
int main() {
static_assert(U<S>::value, "!");
static_assert(not U<R>::value, "!");
static_assert(not U<T>::value, "!");
}
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It doesn't exploit any unevaluated context. Instead, it relies on a trivial using declaration (here named Type) and that's all.
SFINAE and partial template specialization do the rest.
It follows a minimal, working example:
#include<type_traits>
template<typename T, void(T::*)(int)>
using Type = T;
template<typename T, typename = T>
struct U: std::false_type {};
template<typename T>
struct U<T, Type<T, &T::f>>: std::true_type {};
struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};
int main() {
static_assert(U<S>::value, "!");
static_assert(not U<R>::value, "!");
static_assert(not U<T>::value, "!");
}
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
A fairly creative way to do that could be the one below.
It is based on function template and overloading. If you know how tag dispatching works, it should be pretty straightforward to understand.
It follows a minimal, working example:
#include<type_traits>
#include<cstddef>
template<typename T, void(T::*)(int) = &T::f>
constexpr std::true_type f(int) { return {}; }
template<typename T>
constexpr std::false_type f(char) { return {}; }
template<typename T>
constexpr auto detect() { return f<T>(0); }
struct S { void f(int) {} };
struct R { int f(double) { return 42; } };
struct T {};
int main() {
static_assert(detect<S>(), "!");
static_assert(not detect<R>(), "!");
static_assert(not detect<T>(), "!");
}
Can someone think of a way that is vastly different (or at least fairly creative) than the 5 ways I mention here?
If you can use C++14, another way of check if a class has a member variable is by means if template variables.
As an example:
template<typename T, typename = void>
constexpr bool has_foo = false;
template<typename T>
constexpr bool has_foo<T, decltype(std::declval<T>().foo(), void())> = true;
I guess it's probably one of the more compact solution at least.
It follows a minimal, working example:
#include<utility>
template<typename T, typename = void>
constexpr bool has_f = false;
template<typename T>
constexpr bool has_f<T, decltype(std::declval<T>().f(0), void())> = true;
struct S { void f(int) {} };
struct T {};
int main() {
static_assert(has_f<S>, "!");
static_assert(not has_f<T>, "!");
}

Using the detection idiom to determine whether a type has a constructor with a specific signature

I'm playing with the proposal of standard library support for the C++ detection idiom. It is a trait-like metafunction that determines whether a type T has a type member named T::type or a member function with a specific signature, e.g.:
#include <iostream>
template<class...>
using void_t = void;
template<class, template<class> class, class = void_t<>>
struct detect : std::false_type { };
template<class T, template<class> class Operation>
struct detect<T, Operation, void_t<Operation<T>>> : std::true_type { };
template<class T>
using bar_t = decltype(std::declval<T>().bar());
template<class T>
using bar_int_t = decltype(std::declval<T>().bar(0));
template<class T>
using bar_string_t = decltype(std::declval<T>().bar(""));
struct foo
{
int bar() { return 0; }
int bar(int) { return 0; }
};
int main()
{
std::cout << detect<foo, bar_t>{} << std::endl;
std::cout << detect<foo, bar_int_t>{} << std::endl;
std::cout << detect<foo, bar_string_t>{} << std::endl;
return 0;
}
The code above yields the expected output
1
1
0
You can play with a live demo. Now, I would like to test if a type T has a constructor with a specific signature, e.g. T::T(U) with another type U. Is it possible to do that using the detection idiom?
Modify the detect class to allow for variadic args:
template <typename...>
using void_t = void;
template <typename AlwaysVoid, template <typename...> class Operation, typename... Args>
struct detect_impl : std::false_type { };
template <template <typename...> class Operation, typename... Args>
struct detect_impl<void_t<Operation<Args...>>, Operation, Args...> : std::true_type { };
Add an alias that hard-codes a void type:
template <template <typename...> class Operation, typename... Args>
using detect = detect_impl<void, Operation, Args...>;
// ~~~^
Write a detector:
template <typename T, typename... Us>
using has_constructor = decltype(T(std::declval<Us>()...));
Test your class:
static_assert(detect<has_constructor, foo, foo>{}, "!");
DEMO
Even better: std::is_constructible
template<class U>
struct constructable_from {
template<class T>
using test_t = decltype(T(std::declval<U>()));
};
// usage
detect<foo, constructable_from<baz>::test_t> {}
This seems to be working with your code. One can easily extend this to support multi parameter constructors using variadic templates. I don't know whether this is "using the detection idiom", but it's what I've been using myself sometime ago.
My test code on ideone (it's a bit messy, I'm on mobile)

C++ deduce member function parameters

I'm looking to extend the functionality described here but for member functions, what would be the syntax in this case?
Also, the (*) in the template definition, is that de-referencing the function pointer so the compiler can deduce the template arguments?
Would appreciate any input!
Thanks
template <class F> struct ArgType;
template <class R, class T>
struct ArgType<R(*)(T)> {
typedef T type;
};
void f(int) {}
#include <type_traits>
#include <iostream>
int main() {
// To prove
std::cout << std::is_same< ArgType<decltype(&f)>::type, int >::value << '\n';
// To use
ArgType<decltype(&f)>::type a;
}
Pointer-to-members look like Ret (Cls::*)(Args...) [cv-qualifiers] [ref-qualifiers]. So you can extend your class to deduce the first type thusly:
template <class F> struct ArgType;
template <typename Ret, typename Cls, typename T, typename... Args>
struct ArgType<Ret (Cls::*)(T, Args...)> {
using type = T;
};
Note that you can make this more generic by write a metafunction that gives you the nth argument:
template <typename Ret, typename Cls, typename... Args>
struct ArgType<Ret (Cls::*)(Args...)> {
template <size_t N>
struct get_arg {
using type = typename std::tuple_element<N,
std::tuple<Args...>>::type;
};
};
So ArgType<F>::arg<0>::type would be the type you seek.

How can you statically check that a type T exists in a variadic template parameter list

I am trying to statically check to see if a type exists in a variadic template parameter list. However, this template list actually exists within a class that is passed a single type. The answer here shows how to check a list of parameters or a parameter pack, but I am unsure how to test a class that contains variadic templates.
For example
template <typename ...S>
class Services {};
template <typename Services>
class ServiceLocator
{
public:
template <typename T>
T& Resolve()
{
static_assert( check_t_exists_in_variadic_template_within_Services );
return Find<T>();
}
};
What could I write in this static_assert to ensure that each call to this service locator is checked and a compiler error thrown if Resolve is called with a type that does not exist in the template parameter list inside Services?
What I am specicially after is something along the lines of:
static_assert(is_any<T,Services::S...>::value, "T does not exist in Services::S");
Based on François' answer, here's a shorter version that avoids usage of std::tuple and uses std::integral_constant (via true/false_type) and provides a C++14-style contains_v alias. The general idea is the same though.
template <typename T, typename... Args>
struct contains;
template <typename T>
struct contains<T> : std::false_type {};
template <typename T, typename... Args>
struct contains<T, T, Args...> : std::true_type {};
template <typename T, typename A, typename... Args>
struct contains<T, A, Args...> : contains<T, Args...> {};
template <typename T, typename... Args>
constexpr bool contains_v = contains<T, Args...>::value;
You can use it like this:
static_assert(contains_v<float, float, double>,
"failure: float not among <float, double>"); // does not trigger
static_assert(contains_v<int, float, double>,
"failure: int not among <float, double>"); // triggers
One issue with your current code is that ServiceLocator takes a concrete type so you lose the template parameters passed to Services. To retrieve them you need to typedef it somehow so I chose std::tuple since you can't typedef the variadic list directly.
#include <tuple>
#include <type_traits>
template <typename Type, typename Collection>
struct contains;
template <typename Type>
struct contains<Type, std::tuple<>>
{
typedef std::false_type result;
};
template <typename Type, typename ... Others>
struct contains<Type, std::tuple<Type, Others...>>
{
typedef std::true_type result;
};
template <typename Type, typename First, typename ... Others>
struct contains<Type, std::tuple<First, Others...>>
{
typedef typename contains<Type, std::tuple<Others...>>::result result;
};
template <typename ... S>
struct Services
{
typedef std::tuple<S...> Collection;
};
template <typename ServicesType>
class ServiceLocator
{
public:
template <typename T>
T * Resolve()
{
static_assert(contains<T, typename ServicesType::Collection>::result::value, "Fail");
return nullptr;
}
};
class S1 {};
class S2 {};
class S3 {};
int main(int /*argc*/, char * /*argv*/[])
{
Services< S1, S2 > services;
ServiceLocator< decltype(services) > locator;
locator.Resolve< S1 >();
locator.Resolve< S2 >();
locator.Resolve< S3 >(); // triggers static_assert
return 0;
}
I only checked with clang but I hope this helps.
Here is a method using constexpr:
#include <type_traits>
template <typename T>
constexpr bool contains() {
return false;
}
template <typename T, typename A, typename... Tail>
constexpr bool contains() {
return std::is_same<T, A>::value ? true : contains<T, Tail...>();
}
int main()
{
// usage: contains<type_you_want_to_check, type_1, type_2,...>()
static_assert(contains<float, int, double, float>(), "does contain float");
static_assert(contains<float, int, double, char>(), "does not contain float");
}
Aside from being simpler and easier to understand (IMO), this method has the advantage of being easily extensible to other needs, as you can replace the std::is_same call with any other constexpr bool expression, such as std::is_base_of in order to check if the parameter pack contains any base or derived types.

Partial Specialization of tuple contents with variadic arguments

Currently, I'm trying to get some code to react differently to different types. This isn't the exact code, but it gets the message across.
template<class A, class B>
struct alpha {
enum { value = 0 };
};
template<class T, class... Args>
struct alpha<std::tuple<Args...>, T> {
enum { value = 1 };
};
// This gets ignored
template<class T, class... Args>
struct alpha<std::tuple<Args..., std::vector<T> >, T> {
enum { value = 2 };
};
// This gets ignored
template<class T, class... Args>
struct alpha<std::tuple<Args..., T>, T> {
enum { value = 3 };
};
template<class T, class... Args>
struct alpha<T, std::tuple<Args...> > {
enum { value = 4 };
};
template<class... LArgs, class... RArgs>
struct alpha<std::tuple<LArgs...>, std::tuple<RArgs...> > {
enum { value = 5 };
};
int main(int argc, char* argv[]) {
std::cout << alpha<std::tuple<int, double>, double>::value << std::endl; // prints 1
return 0;
}
I've tried more than this code shows, but nothing works so far and I ran across a problem with explicit specialization in a non-namespace scope. For reference, I'm working on gcc 4.6 (the one that comes with oneiric server), which I believe has complete variadic template support. I don't care how ugly it gets if the implementation works to detect the last argument of the parameter pack and the other types as well. Any suggestions?
EDIT:
I wanted to share the solution I used based on the answers (this is an example).
template<typename T> struct tuple_last;
template<typename T, typename U, typename... Args>
struct tuple_last<std::tuple<T,U,Args...>> {
typedef typename tuple_last<std::tuple<U,Args...>>::type type;
};
template<typename T>
struct tuple_last<std::tuple<T>> {
typedef T type;
};
namespace details {
// default case:
template<class T, class U>
struct alpha_impl {
enum { value = 1 };
};
template<class T>
struct alpha_impl<T, T> {
enum { value = 101 };
};
template<class T>
struct alpha_impl<T, std::vector<T>> {
enum { value = 102 };
};
// and so on.
}
template<class T, class... Args>
struct alpha<std::tuple<Args...>, T>
: details::alpha_impl<T, tuple_last<std::tuple<Args...>>;
If you compile using clang, it helpfully reports that (2) and (3) are unusable. The warning for (3), which you expect to be selected, is as follows:
warning: class template partial specialization contains a template parameter that can not be deduced; this partial specialization will never be used
struct alpha<std::tuple<Args..., T>, T> {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
note: non-deducible template parameter 'Args'
template<class T, class... Args>
^
Why is Args not deducible? The C++0x FDIS states at §14.8.2.5/9:
If the template argument list of [a type that is specified in terms of template parameters] contains a pack expansion that is not the last template argument, the entire template argument list is a non-deduced context.
In your specialization, the type std::tuple<Args..., T> is a type that is specified in terms of template parameters Args and T. It contains a pack expansion (Args...), but that pack expansion is not the last template argument (T is the last template argument). Thus, the entire template argument list of the tuple (the entirety of <Args..., T>) is a non-deduced context.
The argument list of the std::tuple is the only place in the template specialization's argument list that Args appears; since it is not deducible from there, it is not deducible at all and the specialization will never be used.
Matthieu M. provides a clever workaround in his answer.
#James provided the why, now let's try to find an alternative.
I would suggest using another level of indirection.
1. Getting the last argument
template <typename T> struct Last;
template <typename T, typename U, typename... Args>
struct Last<std::tuple<T,U,Args...>>
{
typedef typename Last<std::tuple<U,Args...>>::type type;
};
template <typename T>
struct Last<std::tuple<T>>
{
typedef T type;
};
2. Introducing a specialized helper
template <typename T, typename U>
struct alpha_tuple
{
enum { value = 1 };
};
template <typename T>
struct alpha_tuple<T,T>
{
enum { value = 3 };
};
template <typename T>
struct alpha_tuple<std::vector<T>,T>
{
enum { value = 2; }
};
3. Hooking it up
template <typename T>
struct alpha<std::tuple<>, T>
{
enum { value = 1 };
};
template <typename T, typename U, typename Args...>
struct alpha<std::tuple<U, Args...>, T>
{
typedef typename Last<std::tuple<U, Args...>>::type LastType;
enum { value = alpha_tuple<LastType,T>::value };
};
Note that there is no last type for empty tuples, so I had to deal with them in a separate specialization.
If you like to find out whether a tuple as a specific last member, here's a type trait for that:
#include <type_traits>
#include <tuple>
template <typename ...Args> struct back;
template <typename T, typename ...Args> struct back<T, Args...>
{ typedef typename back<Args...>::type type; };
template <typename T> struct back<T>
{ typedef T type; };
template <typename...> struct tuple_has_last : public std::false_type {};
template <typename T, typename... Args> struct tuple_has_last<T, std::tuple<Args...>>
{
static const bool value = std::is_same<typename back<Args...>::type, T>::value;
};
Edit: Oh, I didn't see that Matthieu had already written the exact same thing. Never mind.