Skip to content

Latest commit

 

History

History
213 lines (165 loc) · 5.11 KB

242.md

File metadata and controls

213 lines (165 loc) · 5.11 KB
Info

  • Did you know that ANSI/ISO C++ conforming programs must not rely on a maximum template depth greater than 17 (changed to 1024 in C++11)?

Example

template<auto N> struct type { static constexpr auto id = N; };

template <class T, class... Ts> [[nodiscard]] constexpr auto get(auto& t, const auto id) -> void* {
  if (id == T::id) {
    return std::addressof(std::get<T>(t));
  } else if constexpr(sizeof...(Ts) > 0) {
    return get<Ts...>(t, id);
  } else {
    return nullptr;
  }
}

int main (){
  std::tuple t{"foo", type<0>{}, 42, type<1>{}, type<99>{}, type<42>{}};
  assert((get<type<0>, type<1>>(t, 0)));
  assert((get<type<0>, type<1>>(t, 1)));
  assert(not (get<type<0>, type<1>>(t, 42)));
}

https://godbolt.org/z/16f6qefrh

Puzzle

  • Can you implement function get which returns a void pointer to an object from unique list of inherited types based on run-time id and avoids template depth recursion?

    • Double points for the solution fastest to compile
template <auto N> struct type { static constexpr auto id = N; };

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr auto get(const auto id) -> void *; // TODO
};

int main() {
  data d{
    type<0>{},
    type<1>{},
    type<2>{},
    type<3>{},
    ...
    type<1025>{}
  };

  assert(nullptr != d.get(0));
  assert(nullptr != d.get(1));
  assert(nullptr != d.get(2));
  assert(nullptr != d.get(3));

  ...

  assert(nullptr == d.get(1001));
  assert(nullptr != d.get(10010));

  ...

  assert(nullptr == d.get(1020));
  assert(nullptr != d.get(10200));
  ...
}

https://godbolt.org/z/5x9ndn9nY

Solutions

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr auto get(const auto id) -> void * {
    void* p = nullptr;
    (... or (p = TArgs::id == id ? static_cast<TArgs*>(this) : nullptr));
    return p;
  }
};

https://godbolt.org/z/PcKzoKs64

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr auto get(const auto id) -> void * {
    void* addressofs[]{static_cast<void*>(static_cast<TArgs *>(this))...};
    decltype(id) ids[]{TArgs::id...};
    const auto it = std::find(std::cbegin(ids), std::cend(ids), id);
    return it != std::cend(ids) ? addressofs [ std::size_t(std::distance(std::cbegin(ids), it)) ] : nullptr;
  }
};

https://godbolt.org/z/68KoM6j97

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr void * get(const int id) {
    constexpr int ids[]{ TArgs::id... };

    for (std::size_t i = 0; i < sizeof...(TArgs); ++i) {
      if (ids[i] == id) return this;
    }

    return nullptr;
  }
};

https://godbolt.org/z/7T5qMn9fj

template<class... TArgs>
struct data : TArgs... {

  static constexpr int ids[]{ TArgs::id... };

  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr auto get(const auto id) -> void * {
      auto it = std::find(std::begin(ids), std::end(ids), id );
      if(it == std::end(ids))
      {
          return nullptr;
      }
      return this;
  }
};

https://godbolt.org/z/15YzGPG9b

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  static constexpr int ids[] = { TArgs::id... };
  [[nodiscard]] constexpr auto get(const auto id) -> void * {
      const auto it = std::ranges::find(ids, id);
      return it != std::cend(ids) ? this : nullptr;
  }
};

https://godbolt.org/z/5579683hs

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr auto get(const auto id) -> void * {
      int ids[] = {TArgs::id...};
      for(int i=0; i<sizeof...(TArgs); i++)
        if( id == ids[i])
            return (void*)this;
      return nullptr;
  }
};

https://godbolt.org/z/4b1nzca3P

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }
  [[nodiscard]] constexpr auto get(const auto id) -> void *
  {
      constexpr int N = sizeof ...(TArgs) ;
      int ids[N] = { TArgs::id... };
      void* ptrs[N] = { (dynamic_cast<TArgs*>(this)) ... };
      for( int i = 0; i < N ; ++i )
        if( id == ids[i])
            return ptrs[i];
      return nullptr;
  }
};

https://godbolt.org/z/16bnhre8K

template<class... TArgs>
struct data : TArgs... {
  constexpr explicit(false) data(TArgs... args) : TArgs{args}... { }

  [[nodiscard]] constexpr auto get(const auto id) -> void * {
    return (void*)((TArgs::id == id ? (std::size_t)static_cast<TArgs*>(this) : 0) + ...);
  }
};

https://godbolt.org/z/hsKx6K17s