Variadic Templated class

90 Views Asked by At

Is there a way in C++ to create a templated class that takes any number of arguments in the constructor and can get those when needed?

Example:

#include <string>

template<size_t Size, typename... Types>
class Container
{
public:
    Container(Types... args) 
    {
        // add checks to see if Size = no args
    }

    void get(Types&... args) 
    {
        // getter method
    }
};

int main() 
{
    Container<3, int, double, std::string> container(10, 2.5, "smth");
    int a{};
    double b{};
    std::string c {};
    container.get(a, b, c);
    // expect a = 10, b = 2.5, c = "smth"
    return 0;
}
2

There are 2 best solutions below

0
Jan Schultke On BEST ANSWER

Yes, a solution to your problem already exists in the form of std::tuple:

// note: size_t parameter isn't needed, we can simply get the size using
//       sizeof...(Types)
template<typename... Types>
class Container {
public:
    std::tuple<Types...> stuff;

    // note: in practice, this should use forwarding references and
    //       std::forward instead of taking everything by value
    Container(Types... args) : stuff(args...) {}

    void get(Types&... args) {
        // std::tie creates a tuple of references, letting us
        // assign all members at once
        std::tie(args...) = stuff;
    }
};

You can implement a container that wraps std::tuple, but it doesn't really provide any utility that std::tuple doesn't yet, so we can use it directly:

int main() {
    std::tuple<int, double, std::string> container(10, 2.5, "smth");

    // not so good: decompose using three variables and std::tie
    int a {};
    double b {};
    std::string c {};
    std::tie(a, b, c) = container;

    // better: use structured bindings (C++17)
    auto [aa, bb, cc] = container;
}

Keep in mind that outside of generic programming, you're almost always better off creating your own struct, with meaningful names for the type and the members.

// aggregate type
struct Container {
    int a;
    double b;
    std::string c;
};

int main() {
    Container container{10, 2.5, "smth"};
    // structured bindings also work for aggregate types (C++17)
    auto [a, b, c] = container;
}
0
JeJo On

Is there a way in C++ to create a templated class that takes any number of arguments in the constructor and can get those when needed?

Yes, simply use std::tuple here. Whether you should wrap it into a class template, depends on the further requirements.

#include <tuple> // std::tuple

auto container{ std::make_tuple(10, 2.5, "smth"s) };
// Structured bindings since C++17
auto  [a, b, c] = std::tuple<int, double, std::string>(container);

See a live demo in godbolt.org