Click here to Skip to main content
15,886,518 members
Articles / Programming Languages / C++

Into the Extreme – Fold-Expressions

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
22 May 2023CPOL2 min read 5.3K   2  
Fold-expressions in extreme cases
In this post, you will see how fold-expressions behave when there are no arguments, and also how they behave when there is a single argument.

Fold expressions exist in C++ since C++17 and significantly affect how we treat variadic templates. Back in the day, I wrote about fold-expressions as part of the metaprogramming series, but today, we will explore the extreme cases of fold-expression usages.

An important disclaimer before we start: In this article, code examples show variadic template usages with arguments passed by value, without forwarding them. This is done to simplify them and to focus on the idea behind the examples.

Empty Variadic Parameters

In the case of a unary fold (fold expression without initialization), this case is legal for 3 types of operators: &&, ||, and ,.

Operator &&

C++
template <typename ...Args>
auto and_cond(Args... args) {
    return (args && ...);
}

In case of empty parameters (for the call and_cond()), the function will return true. A reasonable explanation for this decision might be that && operator requires there won’t be any part that evaluates false. In this case, there are no parts at all, so none of the parts evaluate false, and therefore the result should be true.

Operator ||

C++
template <typename ...Args>
auto or_cond(Args... args) {
    return (args || ...);
}

In case of empty parameters, the function will return false. A reasonable explanation for this decision might be that || operator requires that at least one of the parts will evaluate true. Because there are no parts at all, none of them evaluates true, therefore the result is false.

Operator ,

C++
template <typename ...Args>
auto comma_op(Args... args) {
    return (args , ...);
}

For this case, when there are no parameters passed, the result will be void().

Other Operators

For other operators, any call without parameters won’t compile.

Variadic Pack with a Single Parameter

Here, things get a little bit unexpected. When passing only one parameter to a variadic pack, the result will ignore the operator and return the same type & parameter sent to the function (tested on both gcc 13.1.0 & clang 16.0.0). For example:

C++
template <typename ...Args>
auto func(Args ...args)
{
    return (args || ...);
}

int main() {
    using namespace std::string_literals;
    std::cout << func("I am a string"s); // Will print "I am a string"
    return EXIT_SUCCESS;
}

The generated code according to C++ Insights is:

C++
template<>
std::basic_string<char> func<std::basic_string<char>>(std::basic_string<char> __args0)
{
  return std::basic_string<char>(static_cast<std::basic_string<char>&&>(__args0));
}

The same would be for any other operator, including +=, .* and ->.

Binary Fold Expression without Parameters

The same rules for a unary fold expression with a single parameter are applied to a binary fold expression without parameters:

C++
template <typename ...Args>
auto func(Args ...args)
{
    return (args ->* ... ->* "I am a string"s);
}

int main() {
    std::cout << func(); // Will print "I am a string"
    return EXIT_SUCCESS;
}

C++ Insights generated code:

C++
template<>
std::basic_string<char> func<>()
{
  return std::operator""s("I am a string", 13UL);
}

Conclusion

We have to pay close attention to extreme cases and can never count on basic logic to be on our side (who would believe that we can send a std::string to a fold expression that uses || or && operators?).

This article was inspired by a conversation between Daisy Hollman and me. Thank you Daisy! ❤

An unrelated note: My articles’ publish rate decreased during the last several months. The reason is the preparations for Daisy’s and my talk in Core C++ (guess which conversation led to this article).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Israel Israel
Senior C++ developer.
C++ Senioreas blog writer.
Passionate about investigating the boundaries and exploring the advanced capabilities of C++.

Comments and Discussions

 
-- There are no messages in this forum --