Masking Structure Name

Viewed 174

I'm trying to mask a structure name like so:

#define cat_val(l, r) l##r
#define name_mask cat_val(exception_, __COUNTER__)

using i_dont_show_in_rtti = struct name_mask
{
// ...
};

void test()
{
    throw i_dont_show_in_rtti{};
}

This works, but only individually in files. If I include a file that has done this, I'll get a naming conflict (since __COUNTER__ resets per file).

What are my other options? Is there another way I can just mutate a name so it's unintelligable yet unique without making my code unreasonably ugly?

1 Answers

It is possible to do this in completely standard C++14.

  #include <cstdlib>

  template <std::size_t N>
  constexpr std::size_t ct_hash(const char (&str)[N])
  {
      std::size_t hash = 0;
      for (std::size_t i = 0; i < N; ++i)
          hash = (hash << 7) + (str[i] * str[i]); // just an example
      return hash;
  }

  template <std::size_t ... hashes>
  struct mangled;


  // don't have to use all of these, it's just an example. may use __COUNTER__ instead of __LINE__.
  #define HIDE_STRUCT(S) \
  using S = struct mangled<ct_hash(__FILE__), __LINE__, ct_hash(__DATE__), ct_hash(__TIME__), ct_hash(#S)>; \
  template <> struct mangled<ct_hash(__FILE__), __LINE__, ct_hash(__DATE__), ct_hash(__TIME__), ct_hash(#S)>

  HIDE_STRUCT(foo)
  {
      int a;
  };

  HIDE_STRUCT(bar)
  {
      int a; char b;
  };

  void test()
  {
      throw foo{};
  }

  void test2()
  {
      throw bar{};
  }

If you are concerned about possible hash collisions, you can reversibly encrypt your strings instead of hashing them, but this may require C++20 relaxed non-type template parameters (so that you can parametrise over an encrypted string). You will have to write a compile-time encryption function.

Related