Why Do We Need std::addressof, If We Already Have The & Operator?

At first glance, the std::addressof method appears to be redundant. Its  output is the address of the object passed to it. It’s exactly what the & operator have been doing ever since C was developed in the early 70’s:

#include <iostream>
#include <memory>

template<typename T>
void getAddress(T t)
{
	assert( std::addressof(t) == &t);
	std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
	std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

int main()
{
	int i = 0;
	std::cout << "Getting the address of an int type \n";
	getAddress(i);
}

Getting the address of an int type:
Address returned by & operator: 20480024FC1C
Address returned by addressof: 20480024FC1C

C , however, don’t  allow operator overloading while C++ do. More specifically C++ will let you overload the & operator.  Consider instantiating the getAddress template function with the  Buffer class defined below:

#include <iostream>
#include <memory>

class Buffer
{
private:
	static const size_t buffer_size = 256;
	int bufferId;
	char buffer[buffer_size];

public:
	Buffer(int bufferId_) : bufferId(bufferId_) {}
	Buffer* operator&() { return reinterpret_cast<Buffer*> (&buffer); }  //BAD practice, only for  illustration!
};

template<typename T>
void getAddress(T t)
{
	std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
	std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

int main()
{
	Buffer b(1);
	std::cout << "Getting the address of a Buffer type: \n";
	getAddress(b);
}

Getting the address of a Buffer type:
Address returned by & operator: 20480078F50C
Address returned by addressof: 20480078F508

In the Buffer class, the & operator is (badly) overloaded and coerced to return the address of the internal  buffer as the address of the  object. The template implementation expecting a type with an accessible & operator which, it assumes,  returns the address of the object, report the wrong address.  At the same time std::addressof method returns accurately the object’s  address.

So this is why we need std::addressof. It  was introduced into  the boost library and later into the C++ 11 standard as a workaround for a potentially unreliable & operator.

When should you use the std::addressof  method?

You should use std::addressof instead of & in any template implementation taking the address of a user-defined object. Doing so is not a perfect solution as it might  cause unexpected  behavior with types relying on an overloaded & operator (some argue it is an appropriate and just  punishment for developers dabbling in this dark art) .  However, it is possible to  detect the conflict of address reporting and  template expectations in debug builds  with assert( std::addressof(t) == &t) :

template<typename T>
void getAddress(T t)
{
	assert( std::addressof(t) == &t);
	std::cout << "Address returned by & operator: " << std::ios::hex << &t << "\n";
	std::cout << "Address returned by addressof: " << std::ios::hex << std::addressof(t) << "\n";
}

This way you will at least get a heads up while you develop and test your code.

Conclusion

Even prior to C++11 ,  Overloading the & operator has been discouraged, frowned upon  and even prohibited by several C++ coding guidelines such as the one used in aircraft and medical devices software development:   MISRA-C++:2008  (section 5-3-3).  A boost library version of addressof was released in  2002 suggesting that overloading the address operator was perceived as a problem for a long while before the C++ 11 makeover. Yet, the  introduction of the std::addressof  method  into the C++11  standard  is evidence that  the C++ committee  feared too much legacy code will break if the & operator no longer allowed to be overloaded.  I guess this is one case where the jokes about C++ giving you the tools to shoot yourself in the foot are right on the nose.

Binary Integer Literals In C++ 11

Two weeks ago I wrote how happy I was finding out the C++ 14  has gotten around to support binary literals.  However,  If you are stuck with a slightly older compiler (like Visual Studio 2013)   binary literal can also  be easily  expressed in C++ 11!

In his excellent post,  Paul Preney  outlines a tiny framework that will allow writing expressions of the type:

int  can_write_file = 00001_binary;

It is done by user defined literals  processed in by variadic template  functions in a pattern similar to the one outlined in C++ Variadic templates from the ground up.

Roll all the way down to the end of the post for the  complete 50 lines  listing  (including a small demo program)

Using User Defined Types With STL Associative Containers

Consider the struct:

struct ProductKey
{
	std::string brand;
	std::string model;
	int type;
	int version;
};

Using  it in a  std::set will generate a compile time error.

#include  <set>

int main()
{
	std::set<ProductKey> productSet{
		{ "Best Prod", "M1" , 1, 3 },
		{ "Best Prod", "M2" , 32, 3 },
		{ "Value Prod", "P2" , 32, 3 }
	};
}

binary ‘<‘: no operator found which takes a left-hand operand of type ‘const ProductKey’

std::set internal structure calls for a less functor that given, two ProductKey objects, will determine which should be placed in front of the other in an ordered list.

by default std::set  uses std::less,  as we can see from std::set full declaration (line 4):

   		template<

  		class Key,
  		class Compare = std::less<Key>,
  		class Allocator = std::allocator<Key>

  		> class set;

The default less operator employs the ‘<’ operator to compare the  two keys:

template <class T> struct less {
  bool operator() (const T& x, const T& y) const {return x<y;}
  };

As our ProductKey  do not have  a  ‘<’  operator   defined for it, compilation fails.

One possible solution is  to overload the ‘< ‘  operator for the ProductKey   user type. Once it is defined, the default  std::less implementation  can  use this operator  during compilation.  However,  this will actually be a case of doing  too much.   The only consumer of this new ‘<’  operator will be the associative container. There is no need to expose the new operator to any other component which includes  ProductKey   (if nobody needs it don’t implement it!).  It will be more prudent to do the  minimum needed and simply overload the less functor instead.

defining it in the std namespace will enable us to plug our new less functor into the default std::set declaration:

template<> struct std::less<ProductKey>
	{
		bool operator() (const ProductKey& prod1, const ProductKey& prod2) const
		{
			if (prod1.brand != prod2.brand)
			{
				return prod1.brand < prod2.brand;
			}

			if (prod1.model != prod2.model)
			{
				return prod1.model < prod2.model;
			}

			if (prod1.type != prod2.type)
			{
				return prod1.type < prod2.type;
			}

			return prod1.version < prod2.version;
		}
	};

the empty <>  after the template keyword  in line 1 indicate that this is a specialized template.  That is , when the compiler tries to instantiate the less<T> functor  where T is  ProductKey  it will consider our template definition instead of the more  general  std::less functor defined in the standard library.

We can improve the less  functor’s implementation  by  using  std::tie. This function, included in <tuple>,   creates a tuple out  of  the values supplied to it ,  Since ‘< ‘  is defined for the tuple type  by the standard library ,  our std::less functor can be rewritten as

template<> struct std::less<ProductKey>
{
	bool operator() (const ProductKey& prod1, const ProductKey& prod2) const
	{
		return (std::tie(prod1.brand, prod1.model, prod1.type, prod1.version) <
		std::tie(prod2.brand, prod2.model, prod2.type, prod2.version));
	}
};

which is no only more readable,  It’s  also less error prone and not as boring to write!

So the complete example is:


#include <string>
#include <set>
#include <tuple>


struct ProductKey
{
	std::string brand;
	std::string model;
	int type;
	int version;
};

template<> struct std::less<ProductKey>
{
	bool operator() (const ProductKey& prod1, const ProductKey& prod2) const
	{
		return (std::tie(prod1.brand, prod1.model, prod1.type, prod1.version) < 
			std::tie(prod2.brand, prod2.model, prod2.type, prod2.version));
	}
};

int main()
{
	std::set<ProductKey> productSet{
		{ "Best Prod", "M1" , 1, 3 },
		{ "Best Prod", "M2" , 32, 3 },
		{ "Value Prod", "P2" , 32, 3 }
	};
}
Conclusion

Plugging your code into STL’s containers and algorithms,  Enables  you to  make  your code more robust and maintainable with less effort.  Most important it can make it more fun to write.

C++ Variadic templates from the ground up

Its  the new projec’s kickoff meeting. You’ve  been assigned one of the most important tasks: writing a sum function  (yes I know,  work with me here..)

the function needs to accept two values and return their sum. You implant the function and try it out:

double sumf_v1(double a, double  b) 
{
	return a + b;
}

 

int main()
{
	double a = 1;
	double b = 2;

	double  theSum = sumf_v1(a,b);
	cout << "the sum is: " << theSum << endl;
	return 0;
}

the sum is: 3

After completing the implementation you notice that every argument is cast to double.  You decide to rewrite sumf  as a  template function:

template <typename T>
double sumf_v2(T a, T  b)
{
	return a + b;
}

In this version, if the user calls sunf with two integers  the addition operation will be done on two integers leaving only the result to be cast to double,  which is cleaner.

However,  your unit tests reveal a problem:  This test program do not compile,  with several errors. One of which is  ‘double sumf_v2(T,T)’: could not deduce template argument for ‘T’ from ‘int’:

int main()
{
	double  theSum = sumf_v2(1.5,2);
	cout << "the sum is: " << theSum << endl;
	return 0;
}

The compiler has found the first argument in the sumf call   sumf_v2(1.5,2)  and deduced its type as  float (so the template type is set to a float type)
moving over to the next argument, sumf_v2(1.5,2)  the compiler decides  it’s of type int ,  so now the compiler tries to set T to int,  but T is already a float, so compilation stops and a complaint is issued to you.

Fortunately, this is easily fixable by adding another template type:

template <typename T1, typename T2>
double sumf_v3(T1 a, T2  b)
{
	return a + b;
}

Now each value has its own independent  type.  Any  combination of numerical types will compile. All the unit tests compile and pass!  you commit your code and move on.

a couple of days later  you get an email from the project’s lead , your new  function  works great, it’s just that the requirements have changed and now sumf needs to sum-up either 2 or 3 numerical.

Leveraging on your earlier efforts you create and overload of  sumf_v2.
Now have these two functions:

template <typename T1, typename T2>
double sumf_v2(T1 a, T2  b)
{
	return a + b;
}

template <typename T1, typename T2, typename T3>
double sumf_v2(T1 a, T2  b, T3 c)
{
	return a + sumf_v2(b,c);
}

You can now compile and run this program:

int main()
{
	double  theSumOfTwo   = sumf_v2(1.5,2);
	double  theSumOfThree = sumf_v2(1.5,2,3);
	cout << "the sum of two is: " 
	  << theSumOfTwo
	  << " The sum of three is: "
	  << theSumOfThree 
	  << endl;
	return 0;
}

Before you get a chance to  commit your code,  another email arrives informing you requirements have changed again:  in some cases, your function will need to sum 4 arguments!

You wearily  create yet another overload for sumf_v2 

template <typename T1, typename T2, typename T3, typename T4>
double sumf_v2(T1 a, T2  b, T3 c, T4 d)
{
	return a + sumf_v2(b, c, d);
}

so now your sum function  can  sum 2,3 or 4 arguments. But, that not enough for the greedy project lead as he drops by and asks you to also support 5 arguments.

Ok, you’ve  had it! there simply  must  be a better way! besides rewriting the code and adding overloads.  Well, you can have the compiler write all these functions for you when they are needed!

If the long forward didn’t make you forget what this post is all about, you probably  guessed the solution  will involve variadic templates.

let’s define another version for sumf at this time we’ll  define only the prototype as the implementation requires one more step

template <typename... AllT>
double sumf_v3(AllT.. ts)

the  funny typename  keyword with the three dots  in the first line  is called a parameter pack.  It’s our way to tell the compiler that this function template can take any number of arguments (including  0 –   that is no arguments at all)

It’s similar to what we’ve manually done with sumf_v2, by creating overloads  :

template <typename T1, typename T2>
double sumf_v2(T1 a, T2  b);
  
template <typename T1, typename T2, typename T3>
double sumf_v2(T1 a, T2  b, T3 c);

template <typename T1, typename T2, typename T3, typename T4>
double sumf_v2(T1 a, T2  b, T3 c, T4 d);

we told the compiler our function might have 2,3 or 4 arguments.  With the  parameter pack declaration,  we are telling the compiler to create templates with these types:

template <>
template <typename T1>
template <typename T1, typename T2>
template <typename T1, typename T2, typename T3>
template <typename T1, typename T2, typename T3, typename T4>
.
.
.

But which of these overloads   the compiler should create?  this list can be very long.  The answer – only the functions we need – that is the ones that actually get called in the code.  So if there is a function call trying to sum-up  5 arguments the compiler will create :

template <typename T1, typename T2, typename T3, typename T4, typename T5>
double sumf_v3(T1 a, T2  b, T3 c, T4 d, T5 e);

We can employ the strategy used while expanding  sumf_v2 to support more than two values:  calculate sum of arguments by adding the first argument to the  sum of the other n-1  arguments. It’s a recursive pattern that pops up a lot when dealing with variadic templates.   Look again at the implementation of  sumf_v2(T1 a, T2  b, T3 c)  and try to identify this pattern.

To get the  system,  we developed for sumf_v2 ,  to work,  we need a way to isolate the value of the first argument and add it to the sum of the rest argument.  Just we did in the sumf_v2 overloads.

The way to do it in the template function is to define it in a way that  gives the first argument a special name:

template <typename T, typename... RestOfTs>
double sumf_v3(T a , RestOfTs... ts)
{
	return a + sumf_v3(ts...);
}

In this implementation, the first argument gets a type T and a special name a.   The three dots after the ts argument  are called  parameter unpacking it tells the compiler to  pass the rest of the arguments  to the next function.  So in the function call sumf_v3(1, 4, 5.5, 7, 89).  The variable a will be  assigned the value 1 and the generated function implementation will look something like
return  a + sumf_v3(4, 5.5, 7, 89) ;
This is exactly what we wanted!

There is one more small roadblock between us and sumf bliss.  This code will not compile, just yet, giving an error  sumf_v3′: no matching overloaded function found
what?  didn’t we just define a function that will match any possilbe number of  argument ?  its true that    typename…  define  0 or more arguments,  but   our declaration is:

template <typename T, typename... RestOfTs>
double sumf_v3(T a , RestOfTs... ts);

That is one argument followed by a list of 0 or more other arguments. So there has to be at least one argument. Consider the implementation  generated  for sumf_v3(1,2):

return 2 + sumf_v3(3, )

You should read the weird function call  sumf_v3(3, )  as  sumf_v3(3).  I wanted to emphasize the empty list as the second argument . The   implementation for this function call  is :

return 3 + sumf_v3();

which not defined since there has to be at leat the first argument (T a),   The way to resolve this is to give the compiler a better choice when sumf gets called with only one argument :


template <typename T>
double sumf_v3(T a)
{
	return a;
}

When there is  only  one argument,  the compiler will  not try to recursively call a function with an empty list.   Instead , it will just return the received value.  That’s the recursion termination condition:

sumf_v3(1,2)   expands to
return 1 + sumf_v3(2)   expands to
return 1 + 2

so now we have a  pair  of templates

template <typename T>
double sumf_v3(T a)
{
	return a;
}

template <typename T, typename... RestOfTs>
double sumf_v3(T a , RestOfTs... ts)
{
	return a + sumf_v3(ts...);
}

That define a way to generate, on demand, a sum function accepting any number of arguments of any numerical type.  No additional coding needed!

Final notes

Like regular templates, variadic templates can also be used when defining classes and structures.  There are  several methods  in C++ your use to control  the generated code. For example, the template can examine  whether or not a type is a POD (Plain Old Data) and generate different code   for each case. this is called meta programming and will be the subject of a future post.

It’s important to understand that like any other  code generated from  templates, variadic or not,   any  decision  made  is  done in compile time.  By the time  the compiler finish it job all functions and types have defined static attributes in terms of  arguments number and types.