max
max

Reputation: 2657

specialize template member function [SFINAE]

based on this question and the answer provided by "Dave", how to specialize the case for handling the non-integral types to handle a type say QDate (used in Qt for handling date related tasks)?

The function I want to specialize is:

void extract(const std::string str)
{
        std::bitset<sizeof(T) * CHAR_BIT> bs(str.substr(m_start, m_len));
        m_data = static_cast<T>(bs.to_ulong());
}

an std::string of 1s and 0s is supplied to this function and then based on an start and length I need to convert it to the type the template class containing this function was instantiated with. It doesn't make sense when the type is not integral or can't be produced using the std::bitset.

Upvotes: 0

Views: 462

Answers (1)

Praetorian
Praetorian

Reputation: 109159

I'm not sure I understand your use case completely, but I think it's something similar to this

template<typename T>
struct foo
{
    T m_data;
    // others ...

    void extract(const std::string str)
    {
        std::bitset<sizeof(T) * CHAR_BIT> bs(str.substr(m_start, m_len));
        m_data = static_cast<T>(bs.to_ulong());
    }
};

But you want extract to do something different when foo is instantiated with QDate. There are a few different ways to get this done, SFINAE being one of them.

But you can't simply tack on an enable_if expression to extract because for SFINAE to work the substitution failure needs to happen in the immediate context, and T is known by the time foo<T>::extract is instantiated. So add a dummy template parameter to extract that defaults to T.

template<typename U=T>
typename std::enable_if<std::is_same<U, QDate>::value>::type
    extract(const std::string str)
{
  // this will be used when T=QDate
}


template<typename U=T>
typename std::enable_if<!std::is_same<U, QDate>::value>::type
    extract(const std::string str)
{
  // this will be used when T!=QDate
}

If extract is the only thing that changes behavior then another way to accomplish this would be to move all common functionality to another class which foo would inherit from.

template<typename T> 
struct foo_base
{
  // common functionality
};

template<typename T>
struct foo : foo_base<T>
{
  void extract(const std::string str)
  {
    std::bitset<sizeof(T) * CHAR_BIT> bs(str.substr(m_start, m_len));
    m_data = static_cast<T>(bs.to_ulong());
  }
};

// Specialization for QDate
template<>
struct foo<QDate> : foo_base<QDate>
{
  void extract(const std::string str)
  {
    // QDate specific functionality
  }
};

Upvotes: 1

Related Questions