One of the fundamental problems with generic algorithms is that the underlying data is often obscured by (sometimes several) layers of indirection. The standard approach is to have the user supply special-purpose function objects for comparison and assignment, adding unnecessary redundancy, bloat, and function-call overhead to otherwise simple tasks. An automated dereferencing mechanism could be built into these algorithms to eliminate this problem, allowing a higher level of abstraction and better overall productivity. Here is an example of how this might be implemented using recursive template specialization:
Code:
template <class T, bool dereference = true>
struct dref
{
typedef T type;
static
inline
type &
get(type & value)
{
return value;
}
};
template <class T>
struct dref <T*, true>
{
typedef typename dref<T>::type type;
static
inline
type &
get(T * value)
{
return dref<T>::get(*value);
}
};
template <class T>
inline
typename dref<T>::type &
dereference(T & value)
{
return dref<T>::get(value);
}
Notice the second template parameter which would allow the mechanism to be 'switched off' in the (unlikely) event that the actual data *is* the pointer. Here is a test program illustrating how the template would be used:
Code:
#include <iostream>
using namespace std;
template <class T>
void
print(T array[], size_t size)
{
for(size_t i = 0; i < size; ++i)
{
cout << dref<T>::get(array[i]) << endl;
}
}
int
main(void)
{
const size_t size = 5;
int
values[size]
= { 5, 10, 15, 20, 25 },
* p_values[size]
= { &values[0], &values[1], &values[2], &values[3], &values[4] },
** p_p_values[size]
= { &p_values[0], &p_values[1], &p_values[2], &p_values[3], &p_values[4] };
print(values, size);
print(p_values, size);
print(p_p_values, size);
return 0;
}
another example:
Code:
#include <list>
#include <iostream>
#include <cassert>
using namespace std;
template <class Iterator, class Type>
Iterator
find_(Iterator it, Iterator end, const Type & value)
{
while(it != end)
{
if(dereference(*it) == value)
{
return it;
}
++it;
}
return it;
}
int
main(void)
{
const int size = 5;
int values[size] = { 5, 10, 15, 20, 25 };
list <int*> pointers;
for(int i = 0; i < size; ++i)
{
pointers.push_back(&values[i]);
}
assert(find_(pointers.begin(), pointers.end(), 15) != pointers.end());
assert(find_(pointers.begin(), pointers.end(), 21) == pointers.end());
return 0;
}
Is this something that should be considered for future versions of the standard?