Specializing C++ template based on presence/absense of a class member? - c++

Consider the following:
struct A {
typedef int foo;
};
struct B {};
template<class T, bool has_foo = /* ??? */>
struct C {};
I want to specialize C so that C<A> gets one specialization and C<B> gets the other, based on the presence or absence of typename T::foo. Is this possible using type traits or some other template magic?
The problem is that everything I've tried produces a compile error when instantiating C<B> because B::foo doesn't exist. But that's what I want to test!
Edit:
I think ildjarn's answer is better, but I finally came up with the following C++11 solution. Man is it hacky, but at least it's short. :)
template<class T>
constexpr typename T::foo* has_foo(T*) {
return (typename T::foo*) 1;
}
constexpr bool has_foo(...) {
return false;
}
template<class T, bool has_foo = (bool) has_foo((T*)0)>

Another (C++03) approach:
template<typename T>
struct has_foo
{
private:
typedef char no;
struct yes { no m[2]; };
static T* make();
template<typename U>
static yes check(U*, typename U::foo* = 0);
static no check(...);
public:
static bool const value = sizeof(check(make())) == sizeof(yes);
};
struct A
{
typedef int foo;
};
struct B { };
template<typename T, bool HasFooB = has_foo<T>::value>
struct C
{
// T has foo
};
template<typename T>
struct C<T, false>
{
// T has no foo
};

Something like this might help: has_member.
typedef char (&no_tag)[1];
typedef char (&yes_tag)[2];
template< typename T > no_tag has_member_foo_helper(...);
template< typename T > yes_tag has_member_foo_helper(int, void (T::*)() = &T::foo);
template< typename T > struct has_member_foo {
BOOST_STATIC_CONSTANT(bool
, value = sizeof(has_member_foo_helper<T>(0)) == sizeof(yes_tag)
); };
template<class T, bool has_foo = has_member_foo<T>::value>
struct C {};

Related

Can you "hop" between "linked classes" in C++ metaprogramming?

Suppose you have something like this:
template<class D>
class HasDef {
public:
typedef D Def;
};
class A : public HasDef<class B> {};
class B : public HasDef<class C> {};
class C {};
So it is like a "metaprogramming linked list", with type links, via the included typedef Def. Now I want to make a template "Leaf" that, when applied to A, follows the links to yield C:
void f() {
Leaf<A>::type v; // has type C
}
Is it even possible at all to do this? I've tried some methods with std::compare and similar, but none are valid code: everything seems to run into issues with either that C has no Def typedef, or else that the type Leaf<> itself is incomplete when the inner recursive "call" is made so it (or its internal type type) cannot be referenced.
FWIW, the reason I want this is for making a "hierarchical state machine" where that Def represents the default state for each state in the hierarchy, and something a bit more elaborate that this seems to provide a fairly neat and clean "user interface syntax" for it.
I don't really like f(...) in modern code, thus my version uses void_t from C++17:
#include <type_traits>
template<class D>
struct HasDef {
typedef D Def;
};
struct A : HasDef<class B> {};
struct B : HasDef<class C> {};
struct C {};
template <typename T, typename=void>
struct DefPresent : std::false_type{};
template <typename T>
struct DefPresent<T, std::void_t<typename T::Def>> : std::true_type{};
template<typename T, bool deeper = DefPresent<T>::value>
struct Leaf
{
using Type = typename Leaf<typename T::Def>::Type;
};
template<typename T>
struct Leaf<T, false >
{
typedef T Type;
};
static_assert(std::is_same<typename Leaf<C>::Type, C>::value, "C");
static_assert(std::is_same<typename Leaf<B>::Type, C>::value, "B");
static_assert(std::is_same<typename Leaf<A>::Type, C>::value, "A");
https://godbolt.org/z/5h5rfe81o
EDIT: just for completenes, 2 C++20 variants utilizing concepts. Tested on GCC 10
#include <type_traits>
#include <concepts>
template<class D>
struct HasDef {
typedef D Def;
};
struct A : HasDef<class B> {};
struct B : HasDef<class C> {};
struct C {};
template <typename T>
concept DefPresent = requires(T a)
{
typename T::Def;
};
template<typename T>
struct Leaf
{
using Type = T;
};
template<typename T>
requires DefPresent<T>
struct Leaf<T>
{
using Type = Leaf<typename T::Def>::Type;
};
static_assert(std::is_same_v<typename Leaf<C>::Type, C>, "C");
static_assert(std::is_same_v<typename Leaf<B>::Type, C>, "B");
static_assert(std::is_same_v<typename Leaf<A>::Type, C>, "A");
template<typename T>
struct Leaf2
{
template <typename M>
static M test(M&&);
template <DefPresent M>
static auto test(M&&) -> typename Leaf2<typename M::Def>::Type;
using Type = decltype(test(std::declval<T>()));
};
static_assert(std::is_same<typename Leaf2<C>::Type, C>::value, "C");
static_assert(std::is_same<typename Leaf2<B>::Type, C>::value, "B");
static_assert(std::is_same<typename Leaf2<A>::Type, C>::value, "A");
https://godbolt.org/z/vcqEaPrja
You can implement this with SFINAE to separate types that have the typedef from ones that don't when trying to follow them to their leaf. I used the trick from this SO answer here.
The first implementation for Leaf follows the typedef recursively, the second one just defines the type itself as there is no typedef to follow.
Also note I changed your classes to struct for default-public inheritance. Also I changed the order of their definitions for this to compile.
Compiler explorer
#include <type_traits>
namespace detail
{
template<typename T> struct contains_def {
template<typename U> static char (&test(typename U::Def const*))[1];
template<typename U> static char (&test(...))[2];
static const bool value = (sizeof(test<T>(0)) == 1);
};
template<typename T, bool has = contains_def<T>::value>
struct Leaf {
using type = typename Leaf<typename T::Def>::type;
};
template<typename T>
struct Leaf<T, false> {
using type = T;
};
}
template <typename T>
using Leaf = detail::Leaf<T>; // expose Leaf to the global scope
template <typename T>
using Leaf_t = typename Leaf<T>::type; // for convenience
template<typename T>
struct AddDef {
using Def = T;
};
struct C {};
struct B : AddDef<C> {};
struct A : AddDef<B> {};
static_assert(std::is_same_v<Leaf_t<A>, C>);
static_assert(std::is_same_v<Leaf_t<B>, C>);
static_assert(std::is_same_v<Leaf_t<C>, C>);
You could make it a type trait:
#include <utility> // declval
template<class L>
struct Leaf {
template<class M>
static L test(const M&); // match L's without Def
template<class M> // match L's with Def
static auto test(M&&) -> typename Leaf<typename M::Def>::type;
// find matching test() overload, prefer test(M&&):
using type = decltype( test(std::declval<L>()) );
};
template<class L> // bonus helper types
using Leaf_t = typename Leaf<L>::type;
Demo and template resolution # cppinsights

How can I check if these structs has the specific type called "Foo"?

#include <iostream>
/**** I am confused to apply sfinae method here ******/
template <typename T>
struct hasTypeFoo {
//..
static constexpr bool value = true;
};
/////////////////////////////////////////////////
struct A {
using Foo = int;
};
struct B {
};
int main()
{
constexpr bool b1 = hasTypeFoo<A>::value;
constexpr bool b2 = hasTypeFoo<B>::value;
std::cout << b1 << b2;
}
Use std::void_t:
template<typename T, typename = void>
struct hasTypeFoo : std::false_type { };
template<typename T>
struct hasTypeFoo<T, std::void_t<typename T::Foo>> : std::true_type { };
A very good explanation of how std::void_t works, can be found in this question. It is used here to silently reject the specialization if typename T::Foo is ill-formed.
You can do it with partial specialization. e.g.
// primary template
template <typename T, typename = void>
struct hasTypeFoo {
static constexpr bool value = false;
};
// partial specialization for types containing type Foo
template <typename T>
struct hasTypeFoo<T, std::void_t<typename T::Foo>> {
static constexpr bool value = true;
};
LIVE

How do I declare SFINAE class?

Something is not working quite well for me. Is this the way to declare a class, that accepts only floating point template parameter?
template <typename T, swift::enable_if<std::is_floating_point<T>::value> = nullptr>
class my_float;
I fail to define methods outside this class. Doesn't compile, not sure why
Well... not exactly SFINAE... but maybe, using template specialization? Something as follows ?
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T>
class my_float<T, true>
{
// ...
};
If you really want use SFINAE, you can write
template <typename T,
typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
class my_float
{
// ...
};
or also (observe the pointer there isn't in your example)
template <typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
class my_float // ------------------------------------------------^
{
};
-- EDIT --
As suggested by Yakk (thanks!), you can mix SFINAE and template specialization to develop different version of your class for different groups of types.
By example, the following my_class
template <typename T, typename = void>
class my_class;
template <typename T>
class my_class<T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
// ...
};
template <typename T>
class my_class<T,
typename std::enable_if<std::is_integral<T>::value>::type>
{
// ...
};
is developed for in two versions (two different partial specializations), the first one for floating point types, the second one for integral types. And can be easily extended.
You can also use static_assert to poison invalid types.
template <typename T>
class my_float {
static_assert(std::is_floating_point<T>::value,
"T is not a floating point type");
// . . .
};
It's a little bit more direct, in my opinion.
With either of the other approaches, e.g.
template <typename T, bool = std::is_floating_point<T>::value>
class my_float;
template <typename T> class my_float<T, true> { /* . . . */ };
my_float<int,true> is a valid type. I'm not saying that that's a bad approach, but if you want to avoid this, you'll have to encapsulate
my_float<typename,bool> within another template, to avoid exposing the bool template parameter.
indeed, something like this worked for me (thanks to SU3's answer).
template<typename T, bool B = false>
struct enable_if {};
template<typename T>
struct enable_if<T, true> {
static const bool value = true;
};
template<typename T, bool b = enable_if<T,is_allowed<T>::value>::value >
class Timer{ void start(); };
template<typename T, bool b>
void Timer<T,b>::start()
{ \* *** \*}
I am posting this answer because I did not want to use partial specialization, but only define the behavior of the class outside.
a complete workable example:
typedef std::integral_constant<bool, true> true_type;
typedef std::integral_constant<bool, false> false_type;
struct Time_unit {
};
struct time_unit_seconds : public Time_unit {
using type = std::chrono::seconds;
};
struct time_unit_micro : public Time_unit {
using type = std::chrono::microseconds;
};
template<typename T, bool B = false>
struct enable_if {
};
template<typename T>
struct enable_if<T, true> {
const static bool value = true;
};
template<typename T,
bool b = enable_if<T,
std::is_base_of<Time_unit,
T>::value
>::value>
struct Timer {
int start();
};
template<typename T, bool b>
int Timer<T, b>::start() { return 1; }
int main() {
Timer<time_unit_seconds> t;
Timer<time_unit_micro> t2;
// Timer<double> t3; does not work !
return 0;
}

How to implement is_polymorphic_functor?

I'm trying to implement is_polymorphic_functor meta-function to get the following results:
//non-polymorphic functor
template<typename T> struct X { void operator()(T); };
//polymorphic functor
struct Y { template<typename T> void operator()(T); };
std::cout << is_polymorphic_functor<X<int>>::value << std::endl; //false
std::cout << is_polymorphic_functor<Y>::value << std::endl; //true
Well that is just an example. Ideally, it should work for any number of parameters, i.e operator()(T...). Here are few more test cases which I used to test #Andrei Tita's solution which fails for two test-cases.
And I tried this:
template<typename F>
struct is_polymorphic_functor
{
private:
typedef struct { char x[1]; } yes;
typedef struct { char x[10]; } no;
static yes check(...);
template<typename T >
static no check(T*, char (*) [sizeof(functor_traits<T>)] = 0 );
public:
static const bool value = sizeof(check(static_cast<F*>(0))) == sizeof(yes);
};
which attempts to make use of the following implementation of functor_traits:
//functor traits
template <typename T>
struct functor_traits : functor_traits<decltype(&T::operator())>{};
template <typename C, typename R, typename... A>
struct functor_traits<R(C::*)(A...) const> : functor_traits<R(C::*)(A...)>{};
template <typename C, typename R, typename... A>
struct functor_traits<R(C::*)(A...)>
{
static const size_t arity = sizeof...(A) };
typedef R result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<A...>>::type type;
};
};
which gives the following error for polymorphic functors:
error: decltype cannot resolve address of overloaded function
How to fix this issue and make is_polymorphic_functor work as expected?
This works for me:
template<typename T>
struct is_polymorphic_functor
{
private:
//test if type U has operator()(V)
template<typename U, typename V>
static auto ftest(U *u, V* v) -> decltype((*u)(*v), char(0));
static std::array<char, 2> ftest(...);
struct private_type { };
public:
static const bool value = sizeof(ftest((T*)nullptr, (private_type*)nullptr)) == 1;
};
Given that the nonpolymorphic functors don't have an overloaded operator():
template<typename T>
class is_polymorphic_functor {
template <typename F, typename = decltype(&F::operator())>
static constexpr bool get(int) { return false; }
template <typename>
static constexpr bool get(...) { return true; }
public:
static constexpr bool value = get<T>(0);
};
template<template<typename>class arbitrary>
struct pathological {
template<typename T>
typename std::enable_if< arbitrary<T>::value >::type operator(T) const {}
};
The above functor is non-polymorphic iff there is exactly one T such that arbitrary<T>::value is true.
It isn't hard to create an template<T> functor which is true on int and possibly double, and only true on double if (arbitrary computation returns 1).
So an uncompromising is_polymorphic is beyond the scope of this universe.
If you don't like the above (because it clearly takes more than just int, other types simply fail to find an overload), we could do this:
template<template<typename>class arbitrary>
struct pathological2 {
void operator()(int) const {}
template<typename T>
typename std::enable_if< arbitrary<T>::value >::type operator(T) const {}
};
where the second "overload" is tested, and if there are no T such that it is taken, then the first overload occurs for every single type.

Is it possible to selectively define a type in a derived class

I have a class template which looks like this:
template <Base>
struct foo : Base
{
typedef int some_type;
};
and I have a base which looks like this:
struct some_base
{
typedef float some_type;
};
Now foo<some_base>::some_type will be int as the derived foo will hide the Base::some_type. What I would like to do, is that if Base::some_type is defined, use that else, define some_type locally in foo as 'int - so question is, is this possible?
I could invert the relationship and save myself some headache, however it's not very logical in the real application...
Anything is possible with a bit of template metaprogramming :)
Start by writing a metafunction that determines whether a type has a nested type called "some_type". Something like this:
template <typename T>
struct has_some_type
{
typedef char no; // type with sizeof == 1
typedef struct { char x[2]; } yes; // type with sizeof == 2
template <typename X, typename Y = typename X::some_type>
struct foo {};
template <typename X>
static yes test(foo<X>*);
template <typename X>
static no test(...);
static const bool value = (sizeof(test<T>(0)) == sizeof(yes));
};
Now you can do something like this in the derived class:
template <typename T, bool has_some_type>
struct get_some_type;
template <typename T>
struct get_some_type<T, true>
{
typedef typename T::some_type type;
};
template <typename T>
struct get_some_type<T, false>
{
typedef int type; // the default type
};
template <typename base>
class derived : base
{
typedef typename get_some_type<base, has_some_type<base>::value>::type some_type;
...
};
This should work:
struct sfinae_types
{
struct yes { char x; };
struct no { char x[2]; };
};
template<class T>
class has_some_type : sfinae_types
{
private:
template<class U>
static yes test(typename U::some_type *);
template<class U>
static no test(...);
public:
enum { value = (sizeof(yes) == sizeof(test<T>(0))) };
};
template<bool, class T, typename DT>
struct get_some_type
{
typedef DT type;
};
template<class T, typename DT>
struct get_some_type<true, T, DT>
{
typedef typename T::some_type type;
};
struct B1
{
};
struct B2
{
typedef float some_type;
};
template<typename T>
struct D : T
{
typedef typename get_some_type<has_some_type<T>::value, T, int>::type some_type;
};
#include<iostream>
#include<typeinfo>
int main()
{
std::cout << has_some_type<B1>::value << std::endl;
std::cout << typeid(D<B1>::some_type).name() << std::endl;
std::cout << has_some_type<B2>::value << std::endl;
std::cout << typeid(D<B2>::some_type).name() << std::endl;
return(0);
}
And is a slight variation of what HighCommander4 presented a few seconds above...
I guess boost::mpl may come handy here and provide some useful TMP expressions I hand crafted above.
Give struct foo an additional template argument that defaults to int:
template <Base, Typedef = int>
struct foo : Base
{
typedef Typedef some_type;
};
Then foo<some_base, some_base::some_type>::some_type is some_base::some_type.