Reputation: 1637
I want to design a set of functions, such as min
, max
and stddev
, which can support user-defined types. What I plan to do is to let the user pass an Extractor
template argument to these functions. Some sample code as follows:
template <typename T>
struct DefaultExtractor
{
typedef T value_type;
static T value(T &v){
return v;
}
};
template <
typename Extractor=DefaultExtractor<typename std::iterator_traits<InputIterator>::value_type>, //error
typename InputIterator>
typename Extractor::value_type
foo(InputIterator first, InputIterator last)
{
return Extractor::value(*first);
}
This does not compile and the error message is "error: ‘InputIterator’ was not declared in this scope" on the line of typename Extractor=...
.
The reason that I want to put the template Extractor
before InputIterator
is that, when users want to call foo
with a customized Extractor
, they don't need to explicitly provide the type of InputIterator
.
I wonder whether there is a solution to make the code compile, and at the same time it does not require users to provide the parameter InputIterator
explicitly when customized Extractor
is needed.
The code is compiled with g++-4.6.1 -std=c++0x
.
Upvotes: 2
Views: 246
Reputation: 64308
Although I see that you would like to pass the extractor as a template parameter, it is actually more typical to pass an object to the function. It is also more flexible, because it allows you to have extra state that can be passed to the extractor.
Most importantly, it makes it easier to handle the template parameters:
#include <iterator>
#include <list>
template <typename T>
struct DefaultExtractor
{
typedef T value_type;
static T value(T &v){
return v;
}
};
struct MyExtractor {
typedef int value_type;
static int value(int value) { return value; }
};
template <typename Extractor, typename InputIterator>
inline typename Extractor::value_type
foo(
InputIterator first,
InputIterator last,
const Extractor &extractor
)
{
return extractor.value(*first);
}
template <typename InputIterator>
inline typename DefaultExtractor<
typename std::iterator_traits<InputIterator>::value_type
>::value_type
foo(
InputIterator first,
InputIterator last
)
{
typedef DefaultExtractor<typename std::iterator_traits<InputIterator>::value_type> Extractor;
return foo(first,last,Extractor());
}
int main(int argc,char **argv)
{
std::list<int> l;
// Use default extractor
foo(l.begin(),l.end());
// Use custom exractor.
foo(l.begin(),l.end(),MyExtractor());
return 0;
}
Upvotes: 3