After seeing many examples of metaprogramming in C++ that allow for figuring out may properties of classes (such as knowing if a type is a specialization of a template ), or knowing if a class incorporates a given nested type; but I was wondering if is was possible to write a test or trait that determines the inverse of the last one - to check if a given Type
is nested within a class
or struct
.
In other words, I'm looking for the equivalent of the following pseudocode:
template <typename Type> struct is_nested {
enum { value = {__some magic__} };
};
typedef int type1;
struct Something { typedef int internal_type; };
typedef Something::internal_type type2;
//...later, likely at a different scope
is_nested< int >::value; // yields false
is_nested< std::vector<int>::iterator >::value; // yields true
is_nested< type1 >::value; // yields false
is_nested< type2 >::value; // yields true
I know I can use sizeof
to implement yes/no tests, and I presume Type
is part of those tests, but I can't figure out how to plug in some sort of "any viable type" into the test such that I can form an expression like Anytype::Type
.
template struct is_nested { typedef char yes; typedef struct { char u[2]; } no; // Herein lies the problem ???? static yes test( char [ sizeof(Anytype::Type) ] ) ; ???? static no test(...); public: enum { value = sizeof(test(0)) == sizeof(char) }; };
(Note that I don't care nor (can afford to) know what type would Type
be nested in; all it matters is if it is nested in something or not. In other words, this trait should only depend on Type
.)
I'm looking for a C++ solution be it in C++11 or C++03, but in the first case I would welcome it much more if it was backportable.
What you are asking is not possible, but not due to a technical limitation, rather because you can't always tell whether a type name identifies a nested type or not - and templates work with types, not names.
In this case, for instance:
is_nested< std::vector<int>::iterator >::value
You do not know what iterator
is. Consider this class my_vector
:
template<typename T>
struct my_vector
{
typedef T* iterator;
// ...
};
What should is_nested<my_vector<int>::iterator>::value
yield? You probably expect the result to be true
.
However, what is nested here is the alias, not the type itself: the type int*
is not nested. In fact, I expect you would wish the following to yield false
:
is_nested<int*>::value
So here the same is_nested<T>
trait should yield two different results given the same type T
(int*
, in this case). The information based on which is_nested<>
should define value
cannot be retrieved from the type T
itself - and templates work with types, not names.
It may be possible to check if the "canonical type" (the result type after all aliases are resolved) is nested using non-standard features of compilers.
CTTI can get the name of a type at compile time. Then find :
in the string:
#include <vector>
#include "ctti/type_id.hpp"
constexpr bool has_colon(const ctti::detail::string& s, size_t i) {
return i < s.length() ? (s[i] == ':' || has_colon(s, i + 1)) : false;
}
template<typename T>
using is_nested = integral_constant<bool, has_colon(ctti::type_id<T>().name(), 0)>;
typedef int type1;
struct Something { typedef int internal_type; };
typedef Something::internal_type type2;
static_assert(!is_nested< int >::value, "");
static_assert(is_nested< std::vector<int>::iterator >::value, "");
static_assert(!is_nested< type1 >::value, "");
// static_assert(is_nested< type2 >::value, ""); // fail
The 4th check will fail because type2
is just int
, which is not nested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With