For a parametric class C, I want to get always the "primitive" type irrespective of pointer, const or reference modifiers.
template<typename __T>
class C
{
public:
typedef std::some_magic_remove_all<__T>::type T;
}
int main()
{
C<some_type>::type a;
}
For example, for some_type equal to:
int&
int**
int*&
int const &&
int const * const
and so on
I want a is always of type int. How can I achieve it?
If you want to use the standard library more, you can do:
#include <type_traits>
template<class T, class U=
typename std::remove_cv<
typename std::remove_pointer<
typename std::remove_reference<
typename std::remove_extent<
T
>::type
>::type
>::type
>::type
> struct remove_all : remove_all<U> {};
template<class T> struct remove_all<T, T> { typedef T type; };
which removes stuff until that doesn't change the type anymore. With a more recent standard, this can be shortened to
template<class T, class U=
std::remove_cvref_t<
std::remove_pointer_t<
std::remove_extent_t<
T >>>>
struct remove_all : remove_all<U> {};
template<class T> struct remove_all<T, T> { typedef T type; };
template<class T> using remove_all_t = typename remove_all<T>::type;
template<class T> struct remove_all { typedef T type; };
template<class T> struct remove_all<T*> : remove_all<T> {};
template<class T> struct remove_all<T&> : remove_all<T> {};
template<class T> struct remove_all<T&&> : remove_all<T> {};
template<class T> struct remove_all<T const> : remove_all<T> {};
template<class T> struct remove_all<T volatile> : remove_all<T> {};
template<class T> struct remove_all<T const volatile> : remove_all<T> {};
//template<class T> struct remove_all<T[]> : remove_all<T> {};
//template<class T, int n> struct remove_all<T[n]> : remove_all<T> {};
I originally also stripped extents (arrays), but Johannes noticed that this causes ambiguities for const char[], and the question doesn't mention them. If we also want to strip arrays (see also ideas mentioned in the comments), the following doesn't complicate things too much:
#include <type_traits>
template<class U, class T = typename std::remove_cv<U>::type>
struct remove_all { typedef T type; };
template<class U, class T> struct remove_all<U,T*> : remove_all<T> {};
template<class U, class T> struct remove_all<U,T&> : remove_all<T> {};
template<class U, class T> struct remove_all<U,T&&> : remove_all<T> {};
template<class U, class T> struct remove_all<U,T[]> : remove_all<T> {};
template<class U, class T, int n> struct remove_all<U,T[n]> : remove_all<T> {};
or with a helper class but a single template parameter:
#include <type_traits>
template<class T> struct remove_all_impl { typedef T type; };
template<class T> using remove_all =
remove_all_impl<typename std::remove_cv<T>::type>;
template<class T> struct remove_all_impl<T*> : remove_all<T> {};
template<class T> struct remove_all_impl<T&> : remove_all<T> {};
template<class T> struct remove_all_impl<T&&> : remove_all<T> {};
template<class T> struct remove_all_impl<T[]> : remove_all<T> {};
template<class T, int n> struct remove_all_impl<T[n]> : remove_all<T> {};
It is normal if all the variants start looking about the same ;-)
Also you can use the remove_cvref_t function, it has been available since c++20
#include <iostream>
#include <type_traits>
int main()
{
std::cout << std::boolalpha
<< std::is_same_v<std::remove_cvref_t<int>, int> << '\n'
<< std::is_same_v<std::remove_cvref_t<int&>, int> << '\n'
<< std::is_same_v<std::remove_cvref_t<int&&>, int> << '\n'
<< std::is_same_v<std::remove_cvref_t<const int&>, int> << '\n'
<< std::is_same_v<std::remove_cvref_t<const int[2]>, int[2]> << '\n'
<< std::is_same_v<std::remove_cvref_t<const int(&)[2]>, int[2]> << '\n'
<< std::is_same_v<std::remove_cvref_t<int(int)>, int(int)> << '\n';
}
Related
I have a user defined class
template<typename T, int N>
class MyClass
{
// Implementation
};
and I want to check on the instantiation of another class if its template parameter is an instance of MyClass
template<typename T, std::enable_if_t<!is_MyClass<T>, bool> = true>
class MapClass
{
// custom stuff here
};
template<typename T, std::enable_if_t<is_MyClass<T>, bool> = true>
class MapClass
{
// Some more stuff here
};
I tried to implement it like this but my instantiation fails because it requires two parameters. How do I make automatically extract both parameters
template <typename T> struct is_MyClass : std::false_type {};
template <typename T, int N> struct is_MyClass<MyClass<T, N>> : std::true_type {};
Thanks
I suggest to write a trait is_instantiation_of_myClass that uses partial specialization:
template<typename T, int N>
class MyClass {};
template <typename C>
struct is_instantiation_of_myClass : std::false_type {};
template <typename T,int N>
struct is_instantiation_of_myClass<MyClass<T,N>> : std::true_type {};
template <typename C>
constexpr bool is_instantiation_of_myClass_v = is_instantiation_of_myClass<C>::value;
Now you can do SFINAE based on is_instantiation_of_myClass<T> or just plain specialization:
template <typename T,bool = is_instantiation_of_myClass_v<T>>
struct Foo;
template <typename T>
struct Foo<T,true> {
static constexpr bool value = true;
};
template <typename T>
struct Foo<T,false> {
static constexpr bool value = false;
};
int main() {
std::cout << Foo< int >::value << "\n";
std::cout << Foo< MyClass<int,42>>::value << "\n";
}
Live Demo
The below code fails to compile. For some reason inheriting from HasFoo causes IsWrapper to fail. It has something to do with the friend function foo() because inheriting from other classes seems to work fine. I don't understand why inheriting from HasFoo causes the detection idiom to fail.
What is the proper way to detect WithFoo as a Wrapper?
https://godbolt.org/z/VPyarN
#include <type_traits>
#include <iostream>
template<typename TagType, typename ValueType>
struct Wrapper {
ValueType V;
};
// Define some useful metafunctions.
template<typename Tag, typename T>
T BaseTypeImpl(const Wrapper<Tag, T> &);
template<typename T>
using BaseType = decltype(BaseTypeImpl(std::declval<T>()));
template<typename Tag, typename T>
Tag TagTypeImpl(const Wrapper<Tag, T> &);
template<typename T>
using TagType = decltype(TagTypeImpl(std::declval<T>()));
// Define VoidT. Not needed with C++17.
template<typename... Args>
using VoidT = void;
// Define IsDetected.
template<template <typename...> class Trait, class Enabler, typename... Args>
struct IsDetectedImpl
: std::false_type {};
template<template <typename...> class Trait, typename... Args>
struct IsDetectedImpl<Trait, VoidT<Trait<Args...>>, Args...>
: std::true_type {};
template<template<typename...> class Trait, typename... Args>
using IsDetected = typename IsDetectedImpl<Trait, void, Args...>::type;
// Define IsWrapper true if the type derives from Wrapper.
template<typename T>
using IsWrapperImpl =
std::is_base_of<Wrapper<TagType<T>, BaseType<T>>, T>;
template<typename T>
using IsWrapper = IsDetected<IsWrapperImpl, T>;
// A mixin.
template<typename T>
struct HasFoo {
template<typename V,
typename std::enable_if<IsWrapper<T>::value &&
IsWrapper<V>::value>::type * = nullptr>
friend void foo(const T &This, const V &Other) {
std::cout << typeid(This).name() << " and " << typeid(Other).name()
<< " are wrappers\n";
}
};
template<typename Tag>
struct WithFoo : public Wrapper<WithFoo<Tag>, int>,
public HasFoo<WithFoo<Tag>> {};
int main(void) {
struct Tag {};
WithFoo<Tag> WrapperFooV;
// Fails. Why?
static_assert(IsWrapper<decltype(WrapperFooV)>::value,
"Not a wrapper");
return 0;
}
I don't understand why inheriting from HasFoo causes the detection idiom to fail.
Isn't completely clear to me also but surely a problem is that you use IsWrapper<T> inside the body of HasFoo<T> and, when you inherit HasFoo<WithFoo<Tag>> from WithFoo<Tag> you have that WithFoo<Tag> is incomplete when you check it with IsWrapper.
A possible solution (I don't know if acceptable for you) is define (and SFINAE enable/disable) foo() outside HasFoo.
I mean... try rewriting HasFoo as follows
template <typename T>
struct HasFoo {
template <typename V>
friend void foo(const T &This, const V &Other);
};
and defining foo() outside
template <typename T, typename V>
std::enable_if_t<IsWrapper<T>::value && IsWrapper<V>::value>
foo(const T &This, const V &Other) {
std::cout << typeid(This).name() << " and " << typeid(Other).name()
<< " are wrappers\n";
}
What is the proper way to detect WithFoo as a Wrapper?
Sorry but your code is too complicated for me.
I propose the following (simpler, I hope) alternative
#include <type_traits>
#include <iostream>
template<typename TagType, typename ValueType>
struct Wrapper {
ValueType V;
};
template <typename T1, typename T2>
constexpr std::true_type IW_helper1 (Wrapper<T1, T2> const &);
template <typename T>
constexpr auto IW_helper2 (T t, int) -> decltype( IW_helper1(t) );
template <typename T>
constexpr std::false_type IW_helper2 (T, long);
template <typename T>
using IsWrapper = decltype(IW_helper2(std::declval<T>(), 0));
template <typename T>
struct HasFoo {
template <typename V>
friend void foo(const T &This, const V &Other);
};
template <typename T, typename V>
std::enable_if_t<IsWrapper<T>::value && IsWrapper<V>::value>
foo(const T &This, const V &Other) {
std::cout << typeid(This).name() << " and " << typeid(Other).name()
<< " are wrappers\n";
}
template<typename Tag>
struct WithFoo : public Wrapper<WithFoo<Tag>, int>,
public HasFoo<WithFoo<Tag>> {};
int main () {
struct Tag {};
WithFoo<Tag> WrapperFooV;
static_assert(IsWrapper<decltype(WrapperFooV)>::value,
"Not a wrapper");
}
Is there a way to detect, if struct has typedef which is not inherited?
Following code fails on C
#include <iostream>
struct A { };
struct B : public A { typedef A Base; };
struct C : public B {};
template<typename T>
struct to_void
{
typedef void type;
};
template <typename T, typename dummy = void>
struct has_base_typedef : std::false_type {};
template <typename T>
struct has_base_typedef<T, typename to_void<typename T::Base>::type> : std::true_type {};
int main()
{
std::cout << has_base_typedef<A>::value;
std::cout << has_base_typedef<B>::value;
std::cout << has_base_typedef<C>::value;
}
trait for C gives true since Base is inherited (private modifier doesn't help AFAIK)
My goal is to get the snippet to print 010
Small example to play with on ideone.
Basically, you want to block implicit propagation of the Base alias to the derived class, which I don't think is possible. The only way I can think of to achieve something close to what you want is the following:
struct C;
struct A {};
struct B : public A {
using Base = A;
using Derived = C;
};
struct C : public B { };
template<typename T>
struct to_void {
typedef void type;
};
template <typename T, typename dummy = void>
struct has_base_typedef : std::false_type {};
template <typename T>
struct has_base_typedef<T, std::enable_if_t<!std::is_same<typename T::Derived, T>::value,
typename to_void<typename T::Base>::type>> : std::true_type {};
Live Demo
How can I detect a member function has const modifier or not?
Consider the code
struct A {
int member();
int member() const;
};
typedef int (A::*PtrToMember)();
typedef int (A::*PtrToConstMember)() const;
I need something like this:
std::is_const<PtrToMember>::value // evaluating to false
std::is_const<PtrToConstMember>::value // evaluating to true
There you go:
#include <type_traits>
#include <iostream>
#include <vector>
template<typename T>
struct is_const_mem_fn {
private:
template<typename U>
struct Tester {
static_assert( // will always fail
std::is_member_function_pointer<U>::value,
"Use member function pointers only!");
// if you want to report false for types other than
// member function pointers you can just derive from
// std::false_type instead of asserting
};
template<typename R, typename U, typename...Args>
struct Tester<R (U::*)(Args...)> : std::false_type {};
template<typename R, typename U, typename...Args>
struct Tester<R (U::*)(Args...) const> : std::true_type {};
public:
static const bool value =
Tester<typename std::remove_cv<T>::type>::value;
};
struct A {
int member();
int member() const;
};
typedef int (A::*PtrToMember)();
typedef int (A::*PtrToConstMember)() const;
int main()
{
std::cout
<< is_const_mem_fn<PtrToMember>::value
<< is_const_mem_fn<const PtrToMember>::value
<< is_const_mem_fn<PtrToConstMember>::value
<< is_const_mem_fn<const volatile PtrToConstMember>::value
<< is_const_mem_fn<decltype(&std::vector<int>::size)>::value;
}
Output: 00111
EDIT: There's a corner case I forgot to account for in the original answer.
The trait above will choke on a hypothetical member function like this:
struct A {
int member(int, ...) const;
};
because there is no valid specialization of Tester that can be generated for such signature. To fix it, add the following specializations:
template<typename R, typename U, typename...Args>
struct Tester<R (U::*)(Args..., ...)> : std::false_type {};
template<typename R, typename U, typename...Args>
struct Tester<R (U::*)(Args..., ...) const> : std::true_type {};
Below is a simple type trait adapted from here that should allow this.
template <typename T>
struct is_const_mem_func : std::false_type { };
template <typename Ret, typename Class, typename... Args>
struct is_const_mem_func<Ret (Class::*)(Args...) const> : std::true_type { };
I want to define a boost fusion::vector in my class with the size defined by a template parameter. ATM I'm doing this with a specialization of a helper class, but I think there should be a way to do this with boost mpl/fusion or something else in just one line.
namespace detail
{
template<int dim, typename T>
struct DimensionTupleSize
{ };
template <typename T>
struct DimensionTupleSize<1>
{
enum { Dimension = 1 }
typedef boost::fusion::vector<T> type;
};
template <typename T>
struct DimensionTupleSize<2>
{
enum { Dimension = 2 }
typedef boost::fusion::vector<T, T> type;
};
template <typename T>
struct DimensionTupleSize<3>
{
enum { Dimension = 3 }
typedef boost::fusion::vector<T, T, T> type;
};
}
template<int Dim = 2>
class QuadTreeLevel
{
public:
detail::DimensionTupleSize<Dim>::type tpl;
};
Any ideas?
You can do it recursively :
template<int N, class T> struct DimensionTupleSizeImpl
{
typedef typename DimensionTupleSizeImpl<N-1,T>::type base;
typedef typename boost::fusion::result_of::push_back<base,T>::type type;
};
template<class T> struct DimensionTupleSizeImpl<0,T>
{
typedef boost::fusion::vector<> type;
};
template<int N, class T>
struct DimensionTupleSize
: boost::fusion::result_of::
as_vector<typename DimensionTupleSizeImpl<N,T>::type>
{};
If you really want a tuple rather than an array, and you're simply looking for the most succinct solution..,
#include <boost/array.hpp>
#include <boost/fusion/include/boost_array.hpp>
#include <boost/fusion/include/as_vector.hpp>
template<std::size_t DimN, typename T>
struct DimensionTupleSize : boost::fusion::result_of::as_vector<
boost::array<T, DimN>
>::type
{ };
You could use this:
template<int N, typename T>
struct create_tuple
{
private:
template<int i, int n, typename ...U>
struct creator;
template<typename ...U>
struct creator<N,N, U...>
{
typedef boost::fusion::vector<U...> type;
};
template<int i, typename ...U>
struct creator<i, N,T, U...>
{
typedef typename creator<i+1,N,T,U...>::type type;
};
public:
typedef typename creator<1,N,T>::type type;
};
template<int N, class T>
struct DimensionTupleSize
{
typedef typename create_tuple<N,T>::type type;
};