4

Is there a way to generically get the type of a struct, at the top-level in the declaration of said struct, without referring to the actual name of the struct itself?

For example:

#include <type_traits>

struct example {
    using attempt1 = example; // <- obvious, but not what I want
    using attempt2 = decltype(*this); // <- error
    using attempt3 = std::remove_pointer<decltype(this)>::type; // <- error
};

Or:

#include <type_traits>

struct { // anonymous
    //using attempt1 = ...;
    using attempt2 = decltype(*this);
    using attempt3 = std::remove_pointer<decltype(this)>::type;
} x;

Those programs of course fail to compile ("invalid use of 'this' at top level") in C++17 and C++2a mode on GCC 9.x and 10.x, but I'd like to do something like attempt2 or attempt3 where I can get the struct's type without referring to its name ("example" in the first case).

Is this possible?

I took a look through <type_traits> but nothing popped out at me, and I couldn't think of where else to look.

Jason C
  • 38,729
  • 14
  • 126
  • 182
  • 1
    Closest thing I could find was this, see if it somehow helps you https://stackoverflow.com/a/26274842/791430 or this https://stackoverflow.com/a/33232825/791430 Google this with the word `class` rather than `struct` for better results – Omer Tuchfeld Jan 01 '21 at 18:02
  • 1
    maybe this also https://stackoverflow.com/questions/3649278/how-can-i-get-the-class-name-from-a-c-object – Sven Nilsson Jan 01 '21 at 18:02
  • Can you do a `template class SelfTypeHolder { using SelfType = T; }; ` and use it like `class SomeClass: public SelfTypeHolder{}; `, like the curiously recurring template? – Peter - Reinstate Monica Jan 01 '21 at 18:09
  • 1
    Unfortunately it appears the available solutions only work when used in non-static functions of the struct. https://stackoverflow.com/questions/1666802/is-there-a-class-macro-in-c – Sven Nilsson Jan 01 '21 at 18:09
  • Thanks all I'll review the links in the above comments in a bit when I get home, then this comment will self destruct. – Jason C Jan 01 '21 at 18:50
  • @Peter-ReinstateMonica Well, if I understand you correctly, the thing about that is `SelfTypeHolder` still refers to `SomeClass` by its actual name, so for example, I'm not sure (maybe there's a way but I don't know it) how to use that in e.g. an anonymous `struct`. – Jason C Jan 01 '21 at 18:52

1 Answers1

0

Friend injection to the rescue!

Run on gcc.godbolt.org

namespace impl
{
    namespace
    {
        template <typename T>
        struct tag { using type = T; };

        template <int L>
        struct adl_tag
        {
            friend constexpr auto adl_func(adl_tag<L>);
        };

        template <int L, typename T>
        struct adl_writer
        {
            friend constexpr auto adl_func(adl_tag<L>) {return tag<T>{};}
        };

        void adl_func() = delete;

        template <int L>
        struct adl_reader
        {
            using type = typename decltype(adl_func(adl_tag<L>{}))::type;
        };
    }
};

#define KNOWS_SELF_TYPE \
    [[maybe_unused]] void self_type_helper_dummy() \
    { \
        (void)::impl::adl_writer<__LINE__, std::remove_cvref_t<decltype(*this)>>{}; \
    } \
    [[maybe_unused]] static auto self_type_helper() \
    { \
        return ::impl::adl_reader<__LINE__>{}; \
    }

#define SELF_TYPE decltype(self_type_helper())::type

And then...

#include <iostream>
#include <typeinfo>

struct A
{
    KNOWS_SELF_TYPE

    static void foo()
    {
        std::cout << typeid(SELF_TYPE).name() << '\n';
    }
};

int main()
{
    A::foo(); // Prints `1A` (mangled `A`).
}

Unfortunately this solution only works inside of static (and non-static) member functions. For example, it doesn't let you create a typedef to the self type at the class scope. But I assume it might be good enough.

Also it doesn't work in template classes, because self_type_helper_dummy is not being instantiated due to being unused. This could be solved by making it virtual, at the expense of making the class polymorphic.

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207