Search code examples
c++templatesc++20multidispatch

Allow function to be called with arguments in any order


Consider the following code:

#include <concepts>

struct T1 {};

struct T2 {};

struct T3 {};

struct T4 {};

void bar(T1, T2, T3, T4) {
}

template<typename T>
concept IsT = std::same_as<T, T1> || std::same_as<T, T2> ||
              std::same_as<T, T3> || std::same_as<T, T4>;

void foo(IsT auto x1, IsT auto x2, IsT auto x3, IsT auto x4) {
    // How to order the types of x1, x2, x3, x4 and call bar(x?, x?, x?, x?)?
}

int main() {
    foo(T1{},T2{},T3{},T4{}); // ok
    foo(T4{},T3{},T2{},T1{}); // ok
    foo(T3{},T2{},T1{},T4{}); // ok
    // ...
}

My intent is simple:

The user can call foo in any argument order, but finally bar will be called with the arguments in the correct order.

The trivial solution is using brute-force to divide the 24 cases, which is obviously tedious and error-prone.

Is there a non-brute force way to solve this problem? I'm using C++20.


Solution

  • As types are different, you might wrap them in tuple, and get correct types afterward:

    void foo(IsT auto x1, IsT auto x2, IsT auto x3, IsT auto x4) {
        auto t = std::tie(x1, x2, x3, x4);
        bar(std::get<T1&>(t), std::get<T2&>(t), std::get<T3&>(t), std::get<T4&>(t));
    }
    

    Demo