Remove reference with const references
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';
}
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 ;-)
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;