Home > Net >  C 17 What is the difference between a fold expression and if constexpr when using variadic templat
C 17 What is the difference between a fold expression and if constexpr when using variadic templat

Time:04-04

I am trying to understand the difference between two approaches for handling parameter packs / variadic template arguments.

There are two approaches mentioned in the linked article below.

  • fold expression
  • if constexpr (I don't know if this has a formal name)

Link to article

Specifically I am interested to know how the compiler compiles these two approaches, and whether the output is a single function, or whether the output contains recursive function calls.

And more broadly, what are the advantages or disadvantages of using either method, if there are any to be aware of.

(I am thinking about this from the point of view of whether it might be possible to produce a stack overflow from too many nested function calls.)

My interpretation of what is written in the article is that the if constexpr method produces multiple single function calls once compiled, one for each function call which differs by the number of arguments.

However I may have misinterpreted this.

In other words, I interpreted this to mean that if the program contains two function calls to the variadic template function, and one of those function calls contains 3 parameters, and the other contains 5 parameters, then the compiler produces two separate functions, one with 3 arguments, and one with 5. But I may be wrong about this.

Can anyone clarify the situation?

CodePudding user response:

First, this:

template <class... Ts>
void print_all(std::ostream& os, Ts const&... args) {
    ((os << args), ...);
}

is a template that will generate only one function per call like so:

print_all(std::cout, "hello", ' ', "there", 5, "arguments");

Secondly, this:

template <class T, class... Ts>
void print_all(std::ostream& os, T const& first, Ts const&... rest) {
    os << first;

    if constexpr (sizeof...(rest) > 0) {        
        // this line will only be instantiated if there are further
        // arguments. if rest... is empty, there will be no call to
        // print_all(os). 
        print_all(os, rest...);
    }
}

is a template that will generate 5 functions for the same call. The cases are as follows:

  • print_all(std::cout, "hello", ' ', "there", 5, "arguments")
  • print_all(std::cout, ' ', "there", 5, "arguments")
  • print_all(std::cout, "there", 5, "arguments")
  • print_all(std::cout, 5, "arguments")
  • print_all(std::cout, "arguments")

CodePudding user response:

Fold expression is a easy way to operate a parameter pack:

template<typename ...Args>
void print(const Args& ...args) {
    (std::cout << ... << args) << std::endl;
}

It's a syntactic suger that will unfold the .... (Without fold expression, you must use template<typename F, typename ...Args>, template<typename F> and recurs to get every in the ...)


if constexpr is if statement run in comile-time.

template<typename T>
auto print_type_info(const T& t) {
    if constexpr (std::is_integral<T>::value) {
        return t   1;
    } else {
        return t   0.001;
    }
}

// Compiler will instancelize it like:

int print_type_info(const int& t) {
    return t   1;
}

double print_type_info(const double& t) {
    return t   0.001;
}

Conclusion: They are just cleaner syntaces and have no explicit problem while using.

It's my understanding just. If there's any error, please tell me. :)

  • Related