C++11 indexing template parameter packs at runtime in order to access Nth type

C++ is a statically​ typed language. As such the type of all variables needs to be known at compile time (and cannot vary). You want a type that depends on a runtime value. Luckily C++ also features dynamic typing of objects.

Warning: all code in this answer serves only for demonstration of the basic concept/idea. It's missing any kind of error handling, sane interfaces (constructors...), exception safety, ... . So don't use for production, consider using the implementations​ available from boost.

To use this feature you need what's called a polymorphic base class: a class with (at least) one virtual member function from which you derive further classes.

struct value_base {
  // you want to be able to make copies
  virtual std::unique_ptr<value_base> copy_me() const = 0;
  virtual ~value_base () {}
};

template<typename Value_Type>
struct value_of : value_base {
  Value_Type value;

  std::unique_ptr<value_base> copy_me() const {
    return new value_of {value};
  }
};

You can then have a variable with static type of pointer or reference to that base class, which can point to/reference objects from both the base class as well as from any of those derived classes. If you have a clearly defined interface, then encode that as virtual member functions (think of Shape and area (), name (), ... functions) and make calls through that base class pointer/reference (as shown in the other answer). Otherwise use a (hidden) dynamic cast to obtain a pointer/reference with static type of the dynamic type:

struct any {
  std:: unique_ptr<value_base> value_container;

  // Add constructor

  any(any const & a)
    : value_container (a.value_container->copy_me ())
  {}
  // Move constructor

  template<typename T>
  T & get() {
    value_of<T> * typed_container
        = dynamic_cast<value_of<T> *>(value_container.get();)
    if (typed_container == nullptr) {
      // Stores another type, handle failure
    }
    return typed_container->value;
  }

  // T const & get() const;
  // with same content as above
};

template<typename T, typename... Args>
any make_any (Args... && args) {
  // Raw new, not good, add proper exception handling like make_unique (C++14?)
  return {new T(std:: forward<Args>(args)...)};
}

Since object construction is done at runtime the actual type of the pointed to/referenced object may depend on runtime values:

template<typename T>
any read_and_construct (std:: istream & in) {
  T value;
  // Add error handling please
  in >> value;
  return make_any<T>(std:: move (value));
}

// ...

// missing: way of error handling
std::map<int, std:: function<any(std:: istream &)>> construction_map;
construction_map.insert(std::make_pair(1, read_and_construct<double>));
// and more
int integer_encoded_type;
// error handling please
cin >> integer_encoded_type;
// error handling please
any value = construction_map [integer_encoded_type] (cin);

As you may have noticed above code uses also a clearly defined interface for construction. If you don't intend to do lots of different things with the returned any objects, potentially storing them in various data structures over great parts of the time your program is running, then using an any type is most likely overkill and you should just put the type dependent code into those construction functions, too.

A serious drawback of such an any class is its generality: it's possible to store just about any type within it. This means that the (maximum) size of the (actually) stored object is not known during compilation, making use of storage with automatic duration (the "stack") impossible (in standard C++). This may lead to expensive usage of dynamic memory (the "heap"), which is considerably slower than automatic memory. This issue will surface whenever many copies of any objects have to be made, but is probably irrelevant (except for cache locality) if you just keep a collection of them around.

Thus, if you know at compile time the set of types which you must be able to store, then you can (at compile time) compute the maximum size needed, use a static array of that size and construct your objects inside that array (since C++11 you can achieve the same with a (recursive template) union, too):

constexpr size_t max_two (size_t a, size_t b) {
  return (a > b) ? a : b;
}

template<size_t size, size_t... sizes>
constexpr size_t max_of() {
  return max_two (size, max_of<sizes>());
}

template<typename... Types>
struct variant {
  alignas(value_of<Types>...) char buffer[max_of<sizeof (value_of<Types>)...>()];
  value_base * active;

  // Construct an empty variant
  variant () : active (nullptr)
  {}

  // Copy and move constructor still missing!

  ~variant() {
    if (active) {
      active->~value_base ();
    }
  }

  template<typename T, typename... Args>
  void emplace (Args... && args) {
    if (active) {
      active->~value_base ();
    }
    active = new (buffer) T(std:: forward<Args>(args)...);
  }
};

C++ is a statically-typed language, which means that the types of variables cannot be decided or changed at runtime.

Because your array of numbers are input at runtime, it's impossible for you to use the NthTypeOf metafunction in the manner you describe, because NthTypeOf can only depend on a compile-time index.

In your use case, not only are the variables of different type, but the behavior is also different based on user input.

If you want different behavior based on a value determined at runtime, I suggest either a switch statement, a container of std::function, or a heterogeneous container of polymorphic "command" objects.

A solution based on a switch statement is pretty trivial, so I won't bother showing an example.

A std::function is a polymorphic wrapper around a function-like object. You can use a container of std::function to build a sort of dispatch table.

struct StringMatch
{
    void operator()() const
    {
        std::string s1, s2;
        std::cin >> s1 >> s2;
        if (s1 == s2)
            std::cout << "Strings match\n";
        else
            std::cout << "Strings don't match\n";
    }
};

struct SquareRoot
{
    void operator()() const
    {
        float x = 0;
        std::cin >> x;
        std::cout << "Square root is " << std::sqrt(x) <<"\n";
    }

};

int main()
{
    const std::map<int, std::function> commands =
    {
        {1, StringMatch()},
        {2, SquareRoot()},
    };

    int commandId = 0;
    std::cin >> commandId;

    auto found = command.find(commandId);
    if (found != commands.end())
        (*found->second)();
    else
        std::cout << "Unknown command";

    return 0;
}

The map can of course be replaced by a flat array or vector, but then you need to worry about "holes" in the command ID range.


If you need your command objects to be able to do more then execute themselves (like having properties, or support undo/redo), you can use a solution that uses polymorphism and is inspired by the traditional Command Pattern.

class Command
{
public:
    virtual ~Command() {}
    virtual void execute();
    virtual std::string name() const;
    virtual std::string description() const;
};

class StringMatch : public Command
{
public:
    void execute() override
    {
        std::string s1, s2;
        std::cin >> s1 >> s2;
        if (s1 == s2)
            std::cout << "Strings match\n";
        else
            std::cout << "Strings don't match\n";
    }

    std::string name() const override {return "StringMatch";}
    std::string description() const override {return "Matches strings";}
};

class SquareRoot : public Command
{
public:
    void execute() override
    {
        float x = 0;
        std::cin >> x;
        std::cout << "Square root is " << std::sqrt(x) <<"\n";
    }

    std::string name() const override {return "SquareRoot";}
    std::string description() const override {return "Computes square root";}
};

int main()
{
    constexpr int helpCommandId = 0;

    const std::map<int, std::shared_ptr<Command>> commands =
    {
        {1, std::make_shared<StringMatch>()},
        {2, std::make_shared<SquareRoot>()},
    };

    int commandId = 0;
    std::cin >> commandId;

    if (commandId == helpCommandId)
    {
        // Display command properties
        for (const auto& kv : commands)
        {
            int id = kv.first;
            const Command& cmd = *kv.second;
            std::cout << id << ") " << cmd.name() << ": " << cmd.description()
                      << "\n";
        }
    }
    else
    {
        auto found = command.find(commandId);
        if (found != commands.end())
            found->second->execute();
        else
            std::cout << "Unknown command";
    }

    return 0;
}

Despite C++ being a statically-typed language, there are ways to emulate Javascript-style dynamic variables, such as the JSON for Modern C++ library or Boost.Variant.

Boost.Any can also be used for type erasure of your command arguments, and your command objects/functions would know how to downcast them back to their static types.

But such emulated dynamic variables will not address your need to have different behavior based on user/file input.


One possible approach when you want to do something with a run-time dependent type very locally, is to predict run-time values at the compile time.

using Tuple = std::tuple<int, double, char>;

int type;
std::cin >> type;
switch(type) {
    case 0: {
                using ItsType = std::tuple_element<0, Tuple>;
                break;
            }
    case 1: {
                using ItsType = std::tuple_element<1, Tuple>;
                break;
            }
    default: std::cerr << "char is not handled yet." << std::endl;
             break;
}

Only works with small type packs, of course.