Curious
Curious

Reputation: 921

restricting the types using templates in vc++

As far my understanding goes I want to restrict only 2 types int and string for the following class, just like in java template definition with extends.

template<typename T>
typename std::enable_if<std::is_same<T,int>::value || std::is_same<T,string>::value>::type
class ExchangeSort
{
public:
    void bubbleSort(T buffer[], int s);
    void print(T buffer[], int s);
    void bubbleSort(const vector<T>& vec);
};

But if I'm instantiating like below

ExchangeSort<int>* sortArray = new ExchangeSort<int>;

I'm getting errors for the above line ExchangeSort is undefined. What is the problem ?

Upvotes: 1

Views: 34

Answers (2)

Richard Hodges
Richard Hodges

Reputation: 69864

Here's another way which allows the possibility of adding further specialisations down the line:

#include <type_traits>
#include <vector>
#include <string>

//
// Step 1 : polyfill missing c++17 concepts
//
namespace notstd {

    template<class...> struct disjunction : std::false_type { };
    template<class B1> struct disjunction<B1> : B1 { };
    template<class B1, class... Bn>
    struct disjunction<B1, Bn...>
            : std::conditional_t<bool(B1::value), B1, disjunction<Bn...>>  { };
}

//
// Step 2 : create a test to see if a type is in a list
//
namespace detail {

    template<class T, class...Us>
    struct is_one_of : notstd::disjunction< std::is_same<T, Us>... > {};
}

template<class T, class...Us>
static constexpr auto IsOneOf = detail::is_one_of<T, Us...>::value;


//
// Step 3 : declare the default specialisation, but don't define it
//

template<class T, typename Enable = void>
struct ExchangeSort;

//
// Step 4 : define the specialisations we want
//
template<typename T>
class ExchangeSort<T, std::enable_if_t<IsOneOf<T, int, std::string>>>
{
public:
    void bubbleSort(T buffer[], int s);
    void print(T buffer[], int s);
    void bubbleSort(const std::vector<T>& vec);
};


//
// Test
//

int main()
{

    auto esi = ExchangeSort<int>();
    auto ess = ExchangeSort<std::string>();

// won't compile    
//    auto esd = ExchangeSort<double>();

}

Upvotes: 0

SFINAE can be used to conditionally disable function overloads or template specialisations. It makes no sense to try to use it to disable a class template, since class templates cannot be overloaded. You'll be better off using a static assertion:

template<typename T>
class ExchangeSort
{
  static_assert(std::is_same<T,int>::value || std::is_same<T,string>::value, "ExchangeSort requires int or string");
public:
  // The rest as before

As to the errors you were getting, the code didn't make syntactic sense. enable_if can only appear where a type is expected. With functions, it's often used to wrap the return type, in which case it's syntactically similar to what you wrote. But with classes, there's no type between template and the class definition.

Upvotes: 1

Related Questions