I want to check whether a template argument is of reference type or not in C++03. (We already have is_reference in C++11 and Boost).
I made use of SFINAE and the fact that we can't have a pointer to a reference.
Here is my solution
#include <iostream>
template<typename T>
class IsReference {
private:
typedef char One;
typedef struct { char a[2]; } Two;
template<typename C> static One test(C*);
template<typename C> static Two test(...);
public:
enum { val = sizeof(IsReference<T>::template test<T>(0)) == 1 };
enum { result = !val };
};
int main()
{
std::cout<< IsReference<int&>::result; // outputs 1
std::cout<< IsReference<int>::result; // outputs 0
}
Any particular issues with it? Can anyone provide me a better solution?
You can do this a lot easier:
template <typename T> struct IsRef {
static bool const result = false;
};
template <typename T> struct IsRef<T&> {
static bool const result = true;
};
Years ago, I wrote this:
//! compile-time boolean type
template< bool b >
struct bool_ {
enum { result = b!=0 };
typedef bool_ result_t;
};
template< typename T >
struct is_reference : bool_<false> {};
template< typename T >
struct is_reference<T&> : bool_<true> {};
To me it seems simpler than your solution.
However, it was only ever used a few times, and might be missing something.
Related
I am designing a "dereferencer" class, for fun.
I wrote some structs and aliass :
template <class _T>
using deref_type = decltype(*std::declval<_T>());
template <class _T, class _SFINAE>
struct is_derefable : std::false_type {};
template <class _T>
struct is_derefable< _T, deref_type<_T> > : std::true_type
{
using return_type = deref_type<_T>;
};
template<class _T>
using check_derefable = is_derefable<T, deref_type<T>>;
and let's say that there is a variable with type T = std::vector<int**>::iterator, which is the iterator dereferenced into a level-2 pointer, thus has a 3-level dereferenceability.
Here, I want to know the maximum level of "dereferenceability" of an arbitrary type T, at the compile-time.
std::cout << deref_level<std::vector<int**>::iterator>::max << std::endl; // this should prints 3
I thought that it would be way similar to generating a sequence at the compile-time: Template tuple - calling a function on each element
, but I can't draw a concrete picture of it.
Here are what I've tried:
template<class _TF, class _T>
struct derefability {};
template<int _N, class _derefability>
struct deref_level;
template<int _N, class _T>
struct deref_level<_N, derefability<std::false_type, _T>>
{
static const int max = _N;
};
template<int _N, class _T>
struct deref_level<_N, derefability<std::true_type, _T>> :
deref_level<_N + 1, derefability<typename check_derefable<deref_type<_T>>::type, deref_type<_T>>>{};
deref_level<0, derefability<check_derefable<T>::type, T>::max;
but it does not work...(compiler says that max is not a member of tje class) What went wrong?
Here is a recursive implementation using SFINAE directly:
template <class T, class = void>
struct deref_level {
enum : std::size_t { value = 0 };
};
template <class T>
struct deref_level<T, decltype(void(*std::declval<T const &>()))> {
enum : std::size_t { value = deref_level<decltype(*std::declval<T const &>())>::value + 1 };
};
See it live on Wandbox
I don't know what went wrong with your template example, but here's an implementation using a recursive consteval function:
#include <type_traits>
template<typename T, int N = 0>
consteval int deref_level()
{
if constexpr (std::is_pointer<T>::value) {
typedef typename std::remove_pointer<T>::type U;
return deref_level<U, N + 1>();
} else {
return N;
}
}
int main() {
return deref_level<int****>(); // Returns 4
}
After a few days of work, I was able to write code that works without causing an error in MSVC13.
First of all, I needed a robust module to check the dereferenceability of the type.
Since the struct-level SFINAE check fails, I took another method that deduces the return type from overloaded functions with auto->decltype expression, based on the answer: link
template<class T>
struct is_dereferenceable
{
private:
template<class _type>
struct dereferenceable : std::true_type
{
using return_type = _type;
};
struct illegal_indirection : std::false_type
{
using return_type = void*;
};
template<class _type>
static auto dereference(int)->dereferenceable<
decltype(*std::declval<_type>())>;
template<class>
static auto dereference(bool)->illegal_indirection;
using dereferenced_result = decltype(dereference<T>(0));
public:
using return_type = typename dereferenced_result::return_type;
static const bool value = dereferenced_result::value;
};
Now I have a robust dereferenceability-checker, the remaining part becomes far easy.
template< class T,
class D = typename is_dereferenceable<T>::return_type >
struct dereferenceability;
template< class T >
struct dereferenceability<T, void*>
{
using level = std::integral_constant<int, 0>;
};
template< class T, class D >
struct dereferenceability<T, D&>
{
using level = std::integral_constant<int, dereferenceability<D>::level::value + 1>;
};
int main()
{
static_assert(dereferenceability<int>::level::value == 0, "something went wrong");
static_assert(dereferenceability<int****>::iterator>::level::value == 4, "something went wrong");
return 0;
}
I've tested codes above in Visual Studio 2013, and no error occured.
In this example:
template<typename T>
struct ConditionalValue
{
typedef boost::optional<T> type;
};
template<typename T>
struct FindRootValueType
{
typedef typename T::root_type type;
};
template<typename T>
struct FindRootValueType<typename ConditionalValue<T>::type>
{
typedef typename ConditionalValue<T>::type type;
};
template<typename T>
struct Base
{
typedef T value_type;
typedef typename FindRootValueType<value_type>::type root_type;
std::vector<value_type> data;
};
template<typename T>
struct A : public Base<typename ConditionalValue<T>::type>
{
};
template<typename T>
struct B : public Base<A<T>>
{
};
template<typename T>
struct C : public Base<B<T>>
{
};
// C<int>::value_type == B<int>
// C<int>::data == std::vector<B<int>>
// C<int>::data ~= std::vector<std::vector<std::vector<boost::optional<int>>>>
// C<int>::root_type == boost::optional<int>
ConditionalValue is a template alias that simply tries to give an alternate name to boost::optional (such that something else can be used to replace it), and FindRootValueType is a metafunction intended to walk up a chain of types that have definitions similar to those shown at the bottom until it stops at the boost::optional, and then simply returns that.
However as written this does not work (at least not in VS2008). To fix it, the specialization of FindRootValueType must explicitly use boost::optional<T>, not the typedef that should be equivalent to it. (And this defeats the goal of only specifying the underlying implementation type in one place.)
Is this a compiler bug or is this supposed to not work? Or am I just doing something wrong? Is there a better way to write it such that it works as expected?
I also tried reversing the logic thusly:
template<typename T>
struct FindRootValueType
{
typedef T type;
};
// define Base here
template<typename T>
struct FindRootValueType<Base<T>>
{
typedef typename T::root_type type;
};
// define A here
template<typename T>
struct FindRootValueType<A<T>>
{
typedef T type;
};
// define B, C here (no specialisation)
But this doesn't work either (I think because specialisation doesn't follow base types, or possibly it's just the order of definition). I don't want to have to specialise for B, C etc specifically.
(BTW, in both of the above, "not working" means that compiler errors were produced that indicated that it was using the base definition of FindRootValueType, not the specialisation.)
Inspired by this answer to a related question link, I tried the following and it seemed to work:
template<typename T>
struct HasRootType
{
private:
typedef char no;
struct yes { no m[2]; };
static T* make();
template<typename U>
static yes check(U*, typename U::root_type* = 0);
static no check(...);
public:
static bool const value = sizeof(check(make())) == sizeof(yes);
};
template<typename T, bool = HasRootType<T>::value>
struct FindRootValueType
{
typedef typename T::root_type type;
};
template<typename T>
struct FindRootValueType<T, false>
{
typedef T type;
};
// define Base, A, B, C, etc here
Thus redefining the problem to "walk up the types until you find one without a root_type, then return that". I'm still curious why typedef-based specialisation didn't seem to work, though.
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.
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 {};
I'm trying to disable some functions inside a simple template class. The functions that should be removed depend on whether the template argument has certain typedefs.
The example boils down to this:
template<typename T>
struct Foo
{
typename T::Nested foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}
However this gives me a error: no type named ‘Nested’ in ‘struct NoNested’ style error on gcc and clang++ (mind you old versions of both).
Is there an easy way to remove foo when the typedef T::Nested does not exit? (Other than template specialization of the Foo<T> class, as in the real code I have this for about 5 functions with different typedefs.. which would result in 2^5 different specialization )
EDIT:
Since there has been some asking for the motivation for wanting to do this:
I'd like to create something like acompile time FSM for use in a DSL.
I'd like to be able to do this
struct StateA;
struct StateB;
struct StateC;
struct StateA
{
typedef StateB AfterNext;
};
struct StateB
{
typedef StateA AfterPrev;
typedef StateC AfterNext;
};
struct StateC
{
typedef StateB AfterPrev;
};
template<typename T>
struct FSM
{
FSM<typename T::AfterNext> next() { return FSM<T::AfterNext>(); };
FSM<typename T::AfterPrev> prev() { return FSM<T::AfterPrev>(); };
};
So that
FSM<StateA>().next().prev().next().next();
compiles, but
FSM<StateA>().next().prev().prev();
fails.
Note that in reality there would be more transition functions than this, the transition functions would actually do something, and the FSM would store some state.
UPDATE:
I've created proper examples using the methods that have been given so far.
The answers vary in complexity, and while visitors method is the one I'd probably end up using (as it is simplest), my solution (the most complicated) is the only one that actually removes the function.
You can use class template specialization. If you have several functions, then you can move each function to a base class, and specialize each base class.
Try making function foo template itself. It will compile only when called, so you will get the error only when you will try calling it with NoNested class.
You could add a nested typedef to every class, such that compilation only fails when the function is instantiated.
struct null_type; //an incomplete type, you could use a more descriptive name for your particular problem
template<typename T>
struct Foo
{
typename T::Nested foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
typedef null_type Nested;
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo(); //attempt to use incomplete type when used
fnn.bar();
}
It is possible to choose the type T::Nested, if it exists, otherwise void, as follows.
The default choice is void:
template<class T, class = void>
struct NestedReturn
{
typedef void type;
};
A template which always returns void, whatever type you give it:
template<class T>
struct Void
{
typedef void type;
};
A specialisation for types with a Nested nested class by SFINAE. Note that typename Void<typename T::Nested>::type is always void, to match the default second parameter of void in the base template:
template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
typedef typename T::Nested type;
};
And now we use it. Note that foo() is not actually removed when there is no T::Nested, but instantiating it causes an error.
template<typename T>
struct Foo
{
typename NestedReturn<T>::type foo() { return typename T::Nested(); }
int bar() { return 1; }
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}
I suspect that using default function template parameters it would be possible to remove foo() properly using SFINAE, but that's only possible in C++11 (untested guesswork):
template<typename T>
struct Foo
{
template<class N = T::Nested>
N foo() { return N(); }
int bar() { return 1; }
};
Here's how I think I can solve it. It's inspired by user763305's comments.
It requires 2*N specialisations rather than 2^N.
template <typename T>
struct has_nested {
// Variables "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(typename C::Nested*);
template <typename>
static no& test(...);
// If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
// the first overload worked and T has a nested type named type.
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
template<typename T>
struct FooBase
{
int bar() { return 1; }
};
template<typename T, bool>
struct FooImpl : public FooBase<T>
{
};
template<typename T>
struct FooImpl<T,true> : public FooBase<T>
{
typename T::Nested foo() { return typename T::Nested(); }
};
template<typename T>
struct Foo : public FooImpl<T, has_nested<T>::value >
{
};
struct NoNested
{
};
struct WithNested
{
typedef int Nested;
};
int main()
{
Foo<WithNested> fwn;
fwn.foo();
fwn.bar();
Foo<NoNested> fnn;
//fnn.foo();
fnn.bar();
}