0

Hello I'm trying an example and I don't know how to follow. I'm trying to set a map (or some other structure) that saves all the same class/type together. For that, my approach was to take all parameters on the constructor of my class (ResourceManager_t) and everytime that I'm adding a new resource to our map, check if that resource can be added, because was accepted on Ctor.

But I don't know how to fill that std::vector<> to provide any type/class. I've tried with std::any but that doesn't seems to be a right solution.

#include <iostream>
#include <memory>
#include <unordered_map>
#include <vector>
#include <type_traits>
#include <cstdint>
#include <utility>

template <typename...> struct is_one_of;
template <typename F> struct is_one_of<F> { static constexpr bool value = false; };

template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...>
{
    static constexpr bool value = std::is_same<F, S>::value
        || is_one_of<F, T...>::value;
};

template <typename...> struct is_unique;
template <> struct is_unique<> { static constexpr bool value = true; };

template<typename F, typename... T>
struct is_unique<F, T...>
{
    static constexpr bool value = is_unique<T...>::value
        && !is_one_of<F, T...>::value;
};


template<typename... types_t>
struct ResourceManager_t
{
    static constexpr inline bool areAllUnique = is_unique<types_t...>::value;
    static_assert(areAllUnique);
    
    // Ctor.
    ResourceManager_t()
    {
        constexpr auto size = 1 + sizeof...(types_t);
        m_resources.reserve(size);
    }

    template <typename type_t>
    void addResource([[maybe_unused]] type_t add)
    {
        static constexpr auto oneOf = is_one_of<type_t, types_t...>::value;
        static_assert(oneOf);
        const auto name = typeid(type_t).name();
        m_resources[name].emplace_back(add);
    }

    void printMap()
    {
        std::cout << "---------------\n";
        for(auto const& [s, vi] : m_resources)
        {
            std::cout << "[" << s << ": ";
            for(auto const& v : vi)
                std::cout << static_cast<s>(v) << " ";
            std::cout << "]\n";
        }

        std::cout << "---------------\n";
    }

private:
    std::unordered_map<std::string, std::vector</*TODO*/>> m_resources{};
};

int main(int, char *[])
{
    ResourceManager_t<int, char, uint32_t, uint8_t> rm{};
    rm.addResource(1);
    rm.addResource('a');
    rm.addResource(uint8_t{3U});
    rm.addResource(uint8_t{6U});
    // rm.addResource(3.F);

    rm.printMap();

    return 0;
}

I know that my question is not very clear but I've tried a lot of things. Example that I want

Map:
[int    , {1, 2, 3}]
[char   , {'a', 'b', 'c']
[uint8_t, {1U, 2U, 3U}]
// int, char, uint8_t can be changed with an int, or whatever that identifies my value.

If you want a compile/execute example, I've done it with std::vector<int> just to check all other parameters https://godbolt.org/z/hrb1afjxv

max66
  • 65,235
  • 10
  • 71
  • 111
Pablo
  • 82
  • 6
  • Note `std::type_info::name()` is not guaranteed to give different strings for different types. But `std::type_index` is provided specifically for using types as a container key. (This doesn't help with the actual problem in this code.) – aschepler Mar 31 '21 at 12:31

1 Answers1

2

It seems to me that you're looking for a std::tuple<std::vector<types_t>...>.

The following is a full compiling C++17 example, with some simplifications

#include <tuple>
#include <vector>
#include <cstdint>
#include <utility>
#include <iostream>
#include <type_traits>

template <typename T0, typename ... Ts>
struct is_one_of : public std::bool_constant<(std::is_same_v<T0, Ts> || ...)>
 { };

template <typename...>
struct are_unique : public std::true_type
 { };

template <typename T0, typename ... Ts>
struct are_unique<T0, Ts...>
   : public std::bool_constant<not is_one_of<T0, Ts...>::value
                            && are_unique<Ts...>::value>
 { };

template <typename ... Ts>
struct ResourceManager
 {
   static_assert(are_unique<Ts...>::value, "not unique types");

   private:
      std::tuple<std::vector<Ts>...> m_resources{};

   public:
      ResourceManager ()
       { }

      template <typename T0>
      void addResource (T0 add)
       {
         // the static assert is superflous: you get an error from std::get
         // in case of wrong type
         static_assert(is_one_of<T0, Ts...>::value, "wrong type in add");

         std::get<std::vector<T0>>(m_resources).emplace_back(std::move(add));
       }

      void printMap ()
       {
         auto l = [](auto const & vect)
          {
            std::cout << "[" << typeid(decltype(vect[0])).name() << ": ";
            for (auto const & value : vect)
               std::cout << value << " ";
            std::cout << "]\n";
          };

         std::cout << "---------------\n";
         std::apply([&](auto ... vects){ (l(vects), ...); }, m_resources);
         std::cout << "---------------\n";
       }
 };

int main ()
{
    ResourceManager<int, char, std::string, std::uint8_t> rm;

    rm.addResource(1);
    rm.addResource('a');
    rm.addResource(std::uint8_t{3U});
    rm.addResource<std::uint8_t>(6U);
    // rm.addResource(3.F);
    rm.addResource(std::string{"str1"});
    rm.addResource<std::string>("longestStringForYou");

    rm.printMap();
}
max66
  • 65,235
  • 10
  • 71
  • 111