Solve the Forwarding Problem and Simulate Containers of References

Solve the Forwarding Problem and Simulate Containers of References

R1 recently enhanced the standard header with a small reference wrapping library that includes the class template reference_wrapper and the helper functions ref() and cref(). This mini-library library solves the onerous problem of argument forwarding. In addition, it enables you to simulate containers of references. The following sections explain how to do that.

How do you pass references as arguments to algorithms? How do you create containers of references?

Use reference_wrapper and its associated helper functions ref() and cref().

Demonstrating the Problem
C++98 argument deduction rules don’t always let you pass references to functions and algorithms, even when the arguments used are references. This problem is quite common in algorithms that forward their arguments to other callable entities or when constructors forward their arguments to base class constructors. The following code listing demonstrates this problem:

void func(int & ri){ ++ri;}template void g(F f, T t) {  f(t); }int main(){ int n = 0; int& rn=n; g(func, rn); cout << rn << endl; // 0}

You'd expect that after calling g(), the value of n would change to 1. However, func() actually gets a copy of n, not a reference to n. Changing the signature of g() to:

template void g(F f, T& t) 

causes other problems (for instance, when calling g() with rvalue arguments) so this option is ruled out.

This phenomenon is known as the argument forwarding problem. It can lead to bugs that are very hard to detect, especially when working with high-level libraries of algorithms.

Containers manifest a similar problem. Containers of references can be useful in simulating heterogeneous containers?a topic that I've discussed here more than once. However, it's impossible to create such containers in C++98. What may look like a container of references is actually an ordinary container of value objects. This happens because the references are implicitly replaced with value copies of the original argument:

int n=0;int& rn=n;vector  vi;vi.push_back(rn);  ++vi[0]; // modifies vi's copy of n, not n itselfcout <<"original argument: " << rn << endl; // 0cout <<"vector's copy "<< vi[0] <

While this behavior is desirable in many cases, there are times when you really need to store references in containers. Changing the template argument to int& certainly won't help because the generation of the vector specialization produces illegal code constructs such as int& & and int&*:

vector vi; //compilation error

Enter reference_wrapper
std::tr1::reference_wrapper is a CopyConstructible and Assignable wrapper around a reference to an object of type T. It provides a conversion operator to T&, thereby enabling a function template to work on references unmodified. reference_wrapper can be used in places where argument deduction would not deduce a reference. For example, you can rewrite the previous vector example like this:

#include   using std::tr1::reference_wrapper;int n=0;//simulate a vector of int&vector  > vi;vi.push_back( reference_wrapper(n));++vi[0];  cout <<"original argument: " << n <

Second Helpings
The helper function ref():

reference_wrapper ref(T& t);

can be used as a short and convenient alternative to typing reference_wrapper (n):

//same as vi.push_back( reference_wrapper(n));vi.push_back(ref(n));

In places where a reference to a const object is needed, use the helper function cref():

reference_wrapper cref(const T& t);

cref() takes a reference to a const object and returns a matching reference_wrapper that provides an implicit conversion to const T&. For example, you can use cref() to create a std::tr1::tuple object that stores references to const:

#include #includeusing std::tr1::tuple;using std::tr1::make_tuple;A a; const A ca = a;tuple  cra(cref(ca));make_tuple(ref(a)); // tuple  tuple  t(a);
Author's Note: Technically speaking, const T& is a (non-const) reference to const T, not a const reference to T (C++ doesn't have const references anyway). However, the term "const reference" is used frequently in the C++ literature to denote "reference to const".

Similarly, a reference wrapper can be used with the std::tr1::function facility to create references to function objects and references to const function objects:

class Data {private: vector  > records;public: bool operator()(int x, int y) {   records.push_back(make_pair(x, y));   return x < y; }};    Data rec;function  func = ref(rec);

Wrap up
The reference wrapper library is a small, but valuable, enhancement to standard C++. Several other TR1 components, like tuples and std::tr1::function, depend on it. As you have seen, this small library has useful applications in everyday C++ programming as well.

Share the Post:
XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes

ransomware cyber attack

Why Is Ransomware Such a Major Threat?

One of the most significant cyber threats faced by modern organizations is a ransomware attack. Ransomware attacks have grown in both sophistication and frequency over the past few years, forcing

data dictionary

Tools You Need to Make a Data Dictionary

Data dictionaries are crucial for organizations of all sizes that deal with large amounts of data. they are centralized repositories of all the data in organizations, including metadata such as

©2023 Copyright DevX - All Rights Reserved. Registration or use of this site constitutes acceptance of our Terms of Service and Privacy Policy.