How to use a template as a type in a map?

Asked

Viewed 68 times

0

Is there any way to use template as type in a map in C++17?

template<typename T>
std::map<std::string, T/* tipo desconhecido, pode ser qualquer tipo */> map_exemplo;
  • Can you give an example where you would use this ? Templates are usually used in classes or functions where this example would make sense and work perfectly.

  • If I understand, you want to know if there is a way to let the type of each element in the map be any one (i.e. heterogeneous)?

  • I got it, but I need to use a separate for each type, is there any way to access all the elements in a single for? Isac an example(With the problem I described above): https://paste.ofcode.org/Rfd42R7EW2zqbP7z5A3vVy That’s exactly it @Márioferoldi

  • 1

    It seems to me that your real doubt does not play with the question. The goal of templates is to allow defining a specific type to be used in a function or class, which can vary when an object instantiates or calls the function. In the case and according to what you wrote in the existing answer your goal is to have values of different types in the same map.

  • @Isac, nitpick: template also applies to top-level variables.

1 answer

2


introduced the type std::any, a container capable of storing objects of any kind*. Examples:

#include <any>
#include <string>

int main() {
    std::any a = 42; // int
    a = 3.14f; // float
    a = true; // bool
    a = std::string("Hello, World!"); // std::string
}

You can redeem the value of one std::any for its original type with std::any_cast.

In your problem, the type of the element value of the map_exemplo could be defined as std::any, then every time you create a new entry in map_exemplo, the type of the element will not matter. Since not everything is a bed of roses, however, to iterate over the elements in this container, you will need to encode the types you expect the elements to have:

#include <map>
#include <any>
#include <string>

int main() {
    std::map<std::string, std::any> map_exemplo;

    map_exemplo["a"] = 42;
    map_exemplo["b"] = 3.14f;
    map_exemplo["c"] = true;

    for (const auto &[chave, valor] : map_exemplo) {
        if (auto ptr = std::any_cast<int*>(&valor)) {
            // ...
        }
        else if // ...
    }
}

The purpose of std::any is more geared to replace the use of type void * to save user data. In your case, type std::variant would be better for your needs, because with it you can define which types are expected, and the access to objects is done with std::visit:

#include <map>
#include <variant>
#include <string>
#include <cstdio>

// Classe ajudante para sobrecarregar lambdas.
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

int main() {
    std::map<std::string, std::variant<int, float, bool>> map_exemplo;

    map_exemplo["a"] = 42;
    map_exemplo["b"] = 3.14f;
    map_exemplo["c"] = true;

    for (const auto &[chave, valor] : map_exemplo) {
        std::visit(overloaded {
            [] (int i) { std::printf("int: %d\n", i); },
            [] (float f) { std::printf("float: %f\n", f); },
            [] (bool b) { std::printf("bool: %s\n", b ? "true" : "false"); }
        }, valor);
    }
}

* Some rules apply here so that an object can be saved by a std::any, such as satisfying the need to be constructive.

  • Sensational your answer, a little doubt, the types of a Variant can be selected at compilation time?

  • @cYeR, if by "selected at compile time" you say "define which types a Variant data accepts," then yes, this is required. Now, if you meant if "it is possible to use Variant in constant expressions," the answer is also yes, the Std::Variant constructors sane constexpr, except for the copycat.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.