Decltype (* this) equivalent external function body

Is it possible to write a sign that leads to the type of the class in which it is used? How to implement get_class in the example below?

class Foo { typedef get_class::type type; // type = Foo now }; 

Note. I need to write a macro that expands in the cube of a class that is used for several classes, so I can’t just write 'typedef Foo type;'

Use Case:

I have a mirrored (...) macro that generates the infrastructure to iterate over the elements, visit them and view them using their names:

 class Foo { friend std::ostream &operator<<(std::ostream &, const Foo&); reflectable( (int) bar, (double) baz ) } 

reflectable (...) should be a macro, so I can get the types and member names separately as strings for building maps for the search.

I would like the whole reflective class to be thread safe, but if I put my macro reflectable () in a private section, I need to add a friend declaration to the class. I would like to move it to a macro like:

 friend std::ostream &operator<<(std::ostream &, const get_class::type&); 
+5
source share
4 answers

I'm sorry, but I'm sure that in standard C ++ there is no way to get around the class name for a macro anyway. For some unsuccessful attempts, see End of this answer.


However, I believe that your best bet is to slightly change your design. Instead

 friend std::ostream &operator<<(std::ostream &, const get_class::type&); 

provides a public member function

 void stream_to (std::ostream &) const { // Implementation } 

along with a free function template

 template<typename T, typename std:: enable_if<has_stream_to<T>::value>::type * = nullptr> std::ostream &operator<<(std::ostream & s, T const & t) { t.stream_to(s); return s; } 

in the library / program namespace. (Note: I will add the has_stream_to attribute later, for an impatient search for "discover a member function" in the C ++ tag)


Approaches that do not work :

  • Use a pointer to a member function, retrieve the class type using the template function. Reason: &foo inside a class with a member function foo will not point to a function pointer foo . The syntax is required (by standard) as &C::foo (where C is the class name ...).

  • Use the pointer to the data item, retrieve the class type using the template function. For the same reason as above.

  • Use a special member function that returns *this , prints the return type to get the class type. Reason: you need an instance to call this function.

  • Use a pointer to a static member function. Reason: pointers are the same as pointers to free functions, the class name cannot be deduced from them.

  • Use the this pointer in member initialization. Reason: the member type must somehow encode the class type, but auto not allowed for non-static data elements.

+2
source

Note. I need to write a macro that expands in the cube of a class that is used for several classes, so I can’t just write 'typedef Foo type;'

If you can expand the macro when declaring a class, and not in the class body, this might work:

 #include<type_traits> template<typename T> struct Type { using type = T; }; #define struct_with_type(S) struct S: Type<S> struct_with_type(Foo) {}; int main() { static_assert(std::is_same<Foo::type, Foo>::value, "!"); } 

Note that the example suggested with my previous answer is not valid:

 struct Foo { static constexpr auto get_type() -> std::decay_t<decltype(*this)>; using type = decltype(get_type()); }; 

It only compiles with GCC due to this compiler error.
Something I would not use in production code.

However, if you like it, the following compilation and something close to this solution:

 #include<type_traits> #include<utility> #define add_type() constexpr auto type() -> std::decay_t<decltype(*this)>; template<typename T> using get_type = decltype(std::declval<T>().type()); struct Foo { add_type(); }; int main() { static_assert(std::is_same<get_type<Foo>, Foo>::value, "!"); } 
0
source

This is not a good solution, but it can do the trick for you on simple functions. I still haven't expanded it for templates and other things like variable functions:

 #define FUNCTION_DECL(R, N, ...) \ RN(__VA_ARGS__); #define DEFINE_FRIEND_OPERATOR(CLASS_NAME, MEMBERS) \ friend std::ostream& operator<<(std::ostream& s, CLASS_NAME const& f) \ { \ std::cout << #CLASS_NAME << ':' << std::endl; \ MEMBERS \ return s; \ } #define S_(X) #X #define S(X) S_(X) #define STREAM_FUNCTION(R, N, ...) \ s << " " #R " " #NS((__VA_ARGS__)) << std::endl; 

I see no portable way to have a class name other than passing it to a macro, so the type is skipped.

Now you can put macros over the corresponding heading (and find the best / more suitable names ...) that will be included for each class. There you would:

 class Foo { #define FOO_MEMBERS \ MEMBER(int, f0, int, int, int) \ MEMBER(double, f1, double) \ MEMBER(void, f2, char const) public: #ifdef MEMBER #undef MEMBER #endif #define MEMBER FUNCTION_DECL FOO_MEMBERS #undef MEMBER private: #define MEMBER STREAM_FUNCTION DEFINE_FRIEND_OPERATOR(Foo, FOO_MEMBERS) #undef MEMBER }; 

For map entries, you will have similar macros that generate an initialization list in the constructor, for example, here .

0
source

As I mentioned in the comments, this sounds like an XY issue. Instead, add an indirection layer:

 class Foo { friend class reflectable_access; reflectable( (int) bar, (double) baz ) }; 

Now reflectable_access can access things added by your reflectable macro and provide them to other users who need access to them.

0
source

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


All Articles