开发者

How to specialize this template (paying attention to return type)

I'd like to specialize following template:

template <typename T, int P>
T item(size_t s);

into something like that:

template<int P>
T item<typename T>(size_t s)
{
//for all numeric types
    return static_cast<T>(rand());
}

template <int P>
string item<string>(size_t s)
{
    return "asd开发者_JAVA百科f";
}


You can't partially specialize function templates like that. Template partial specialization is only for class templates.

However, you can use boost::enable_if to "emulate" the kind of function template partial specialization you're looking for.

// Specialization for std::string
//
template <int P, typename T>
T item(size_t, typename boost::enable_if<boost::is_same<T, std::string> >::type* = 0)
{
   ....
}

// Specialization for int
//
template <int P, typename T>
T item(size_t, typename boost::enable_if<boost::is_same<T, int> >::type* = 0)
{
    ....
}

This way, if you call item<5, std::string>(10) you'll invoke the first function, and if you call item<5, int>(10) you'll invoke the second function.

Alternatively, if you don't want to use Boost for some reason, another work-around is to create a dispatcher class template, which of course can be partially specialized.


Both are going to require partial specialization. The first is going to require SFINAE. Since function templates can only be fully specialized you'll have to use a helper object of some sort.

template <typename T, int P>
T item(size_t s);

template < typename T, typename Enable = void >
struct item_
{
  template < int P >
  T apply(size_t s);
};

template < typename T >
struct item_<T, typename enable_if< is_numeric<T> >::type >
{
  template < int P >
  static T apply(size_t s) { return static_cast<T>(rand()); }
};

template < >
struct item_<std::string, void>
{
  template < int P >
  static std::string apply(size_t s) { return "NSTHEOSUNTH"; }
};

template < typename T, int P >
T item(size_t s) { return item_<T>::template apply<P>(s); }

Alternatively you might consider tag dispatching:

struct numeric_tag {};
struct string_tag {};
struct wtf_tag {};

template < typename T, int P >
T item(size_t s, numeric_tag) { return static_cast<T>(rand()); }
template < typename T, int P >
T item(size_t s, string_tag) { return "SNTHEO"; }
template < typename T, int P >
T item(size_t s)
{
  item(s, if_
          < 
            is_numeric<T>
          , numeric_tag
          , typename if_
            <
              is_same< std::string, T >
            , string_tag
            , wtf_tag
            >::type
          >::type());
}

Or you could mix some metafunction classes up to match with tags and use a vector of pairs...iterate through them testing each first (the metafunction class) and returning the second (the tag) to pick an implementation.

There's lots and lots and lots of ways to go about it.


Just to be clear: you cannot specialise function templates at all. You can overload them, you can't specialise them.

Correct binding of partial specialisations of function templates, if they existed, would be given by something like:

template<class T, class U> X f(T,U);

specialise template<class A, class B> X f(A,B) 
  with template <class K> <K,K*>;

Template classes have an easier specialisation specification because they're uniquely identified by name, functions overload, so that isn't enough.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜