NikitaRock
NikitaRock

Reputation: 353

Deducing variadic template depending on argument count

Imagine I have two functions:

void string(const char *str)
{
    std::cout << "this is string" << std::endl;
}

void number(const char *str, double f)
{
    std::cout << "this is number" << std::endl;
}

I want to write a generic wrapper so that be able to call format() like this:

int main() {
    format("single arg");
    format("format string", 1.0);
    format("single arg", "format string", 1.0);
    format("format string 1", 1.0, "just string arg", "format string 2", 2.0);
    return 0;
}

That is if arguments come in pair {string, number}, then invoke number(); otherwise call string(). Obviously, it can be done only unpacking arguments right-to-left. I've tried to implement it following (wrong) way:

template<class T>
void operation(T first)
{
    string(first);
}

template<class T, class U = float>
void operation(T first, U second)
{
    number(first, second);
}

template<class ... ARGS>
void format(ARGS ... args)
{
    auto last = (args, ...);
    using last_type = typename decltype(last);
    if constexpr (std::is_arithmetic_v<last_type>)
        (..., operation(args, last));
    else
        (..., operation(args)); 
}

The problem is that while unpacking operation(args, last) we will get both args and last floats. I believe there's some easy way to achieve what I want (without relying on tuples etc).

Upvotes: 1

Views: 76

Answers (1)

Quentin
Quentin

Reputation: 63114

Here is a proof-of-concept using only overload resolution. I'm not sure how scalable it is, though.

void format() {}

void format(char const *str) {
    string(str);
}

template <class... Args>
void format(char const *str, char const *nextStr, Args... args);

template <class... Args>
void format(char const *str, double f, Args... args);

template <class... Args>
void format(char const *str, char const *nextStr, Args... args) {
    string(str);
    format(nextStr, args...);
}

template <class... Args>
void format(char const *str, double f, Args... args) {
    number(str, f);
    format(args...);
}

See it live on Godbolt.org

Upvotes: 5

Related Questions