C ++. Do you know if a type / class is nested?

After looking at many examples of metaprogramming in C ++ that allow you to find out if the properties of classes (for example, know whether a type is a specialization of a template ) or knowing whether a class includes this nested type; but I was wondering if it is possible to write a test or a sign that determines the last one, to verify that this Type nested in a class or struct .

In other words, I am 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 that I can use sizeof to implement yes / no tests, and I assume that Type is part of these tests, but I cannot figure out how to connect some kind of β€œany viable type” to the test so that I can form an expression, similar to 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 do not care, and (I can afford it) to know what type the Type will be nested, all that matters is if it is nested by something or not. In other words, this symptom should depend only on Type .)

I am looking for a solution in C ++ in C ++ 11 or C ++ 03, but in the first case I would have welcomed it much more if it was backportable.

+6
source share
2 answers

What you are asking is impossible, but not because of technical limitations, but because you cannot always determine whether a type name is a nested type or not, and templates work with types and not with names.

In this case, for example:

 is_nested< std::vector<int>::iterator >::value 

You do not know what iterator . Consider this my_vector class:

 template<typename T> struct my_vector { typedef T* iterator; // ... }; 

What should be is_nested<my_vector<int>::iterator>::value ? You probably expect the result to be true .

However, what is nested here is an alias, not the type itself: the int* type is not nested. In fact, I expect you to want the following to get false :

 is_nested<int*>::value 

So, here the same trait is_nested<T> should give two different results with the same type T ( int* in this case). Information based on the fact that is_nested<> should determine value cannot be obtained from the type T - and templates work with types, not names.

+1
source

It may be possible to verify that the "canonical type" (the result type after resolving all the aliases) is nested using non-standard compiler functions.

CTTI can get the type name at compile time. Then find : in the line:

 #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 fourth check will fail because type2 is just an int that is not nested.

0
source

Source: https://habr.com/ru/post/944068/


All Articles