Variadic Functions

Capturing Lvalues and Rvalues in Variadic Functions

How can I write a variadic function that can accept both lvalue and rvalue arguments?

Abstract art representing computer programming

To write a variadic function that can accept both lvalue and rvalue arguments, you can use forwarding references (also known as universal references) in the parameter pack. Forwarding references are declared using the && syntax with a deduced type (auto or template type parameter).

Here's an example:

#include <iostream>

// Variadic function using forwarding references
template <typename... Types>
void PrintValues(Types&&... Args) {
  (std::cout << ... << std::forward<Types>(Args))
    << '\n';  
}

int main() {
  int a = 10;
  const std::string b = "hello";
  
  // lvalues
  PrintValues(a, b);

  // rvalues
  PrintValues(20, std::string("world"));
}
10hello
20world

In this example, PrintValues() uses forwarding references Types&&... Args to capture both lvalue and rvalue arguments. Inside the function, std::forward<Types>(Args) is used to forward the arguments to std::cout while preserving their value category.

When PrintValues() is called with lvalue arguments a and b, the compiler deduces the template arguments as int& and const std::string& respectively. The arguments are forwarded as lvalue references.

When PrintValues() is called with rvalue arguments 20 and std::string("world"), the compiler deduces the template arguments as int&& and std::string&& respectively. The arguments are forwarded as rvalue references.

By using forwarding references, the variadic function can accept and forward both lvalue and rvalue arguments, avoiding unnecessary copying and enabling perfect forwarding.

It's important to note that if you don't need to modify the arguments and want to avoid potential dangling references, you can use const Types&... instead of Types&&... to capture lvalues and rvalues as const references.

template <typename... Types>
void PrintValuesConstRef(const Types&... Args) {
  (std::cout << ... << Args) << '\n';
}

This version captures both lvalues and rvalues as const references, preventing modification and avoiding dangling references, but it does not enable perfect forwarding.

Answers to questions are automatically generated and may not have been reviewed.

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved