Re: Deprecate the use of plain pointers as standard container iterators
Dave Harris wrote:
#include <vector>
//void func( std::vector<int>::iterator );
template <typename T> void func( T );
template void func( std::vector<int>::iterator );
void func( double x );
void test() {
func( 1 );
}
This fails to compile because there is no definition of the template for
the int argument. If I delete the template and uncomment the simple
iterator overload, the code does compile.
Yes, I think I see what you mean. And it's true, templates do interact
awkwardly with implicit conversions. Basically, what is needed is:
(a) one or more functions with specific, known parameter types;
overload resolution should select these for calls with actual
parameters matching or convertible to these formal parameter types;
plus...
(b) one or more functions with indeterminate parameter types, which
won't be selected by overload resolution in preference to the
"concrete" functions above, but which will match some implementation
dependent typedefs IF those typedefs aren't matched (directly or by
conversion) by one of the concrete functions.
It actually is possible to express this in C++, but it does require
some metaprogramming gymanstics (which can be mostly hidden by
boost::enable_if and boost::is_same). Here's an example:
#include <vector>
#include "boost/utility/enable_if.hpp"
#include "boost/type_traits/is_same.hpp"
using boost::enable_if;
using boost::is_same;
void func( double x );
void func( int* p );
typedef std::vector<int>::iterator iiter_t;
template <typename T>
void
func( T, typename enable_if< is_same< T, iiter_t > >::type* = 0 );
int main()
{
std::vector<int> vi (5);
func( vi.begin() );
func( 1 );
}
The definitions can live in a separate translation unit:
#include <iostream>
#include <vector>
#include "boost/utility/enable_if.hpp"
#include "boost/type_traits/is_same.hpp"
using boost::enable_if;
using boost::is_same;
typedef std::vector<int>::iterator iiter_t;
template <typename T>
void func( T t, typename enable_if< is_same< T, iiter_t > >::type* )
{
std::cout << "Template version called: " << *t << std::endl;
}
template void func( std::vector<int>::iterator, void* );
void func( double x )
{
std::cout << "Double version called: " << x << std::endl;
}
void func( int* p )
{
std::cout << "int* version called: " << *p << std::endl;
}
This works and "does the right thing" regardless of whether the
vector<int>::iterator is an int* or not.
Whether this is "simpler" than demanding that vectors not use pointers
as their iterator types is, of course, another question. But this
technique works today, without the multi-year process that would be
involved in changing the standard in a way that outlaws existing
standard library implementations.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]