Danqi Wang
Danqi Wang

Reputation: 1637

On Default template Function Parameter

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

Answers (1)

Vaughn Cato
Vaughn Cato

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

Related Questions