Playdoh Legs
Playdoh Legs

Reputation: 19

How do you check if a specific operator is defined for a template in C++?

I want to throw an exception when a type that does not have the less than (<) operator defined is passed into 'myclass'. I added in some sample code to help explain what I want to do.

template<typename T>
class CLASS {
public:
    CLASS() 
    {
        //if('T' does not have '<' operator defined)
        //{
        //  throw exception;
        //}     
    }

private:
    T mProperty;
};

class PlainClass {
public:
    PlainClass() {}
private:
    int num = 0;
};

int main()
{
    CLASS<int> ok;              //ok
    CLASS<PlainClass> error;    //throws exception

    return 0;
}

Note for future viewers: Nacl's answer to the question resolves the problem and Columbo provides a more elegant solution.

Upvotes: 0

Views: 203

Answers (2)

NaCl
NaCl

Reputation: 2723

It's very useless. There is really no usecase to check this with exceptions as they are thrown at run time and templates work at compile time. Use static_assert as mentioned by Columbo.

But you can do it for example like this:

namespace somenamespace
{
    typedef char no[7];
    template<typename T> no& operator<(const T&, const T&);

    template<typename T>
    struct checker
    {
        enum { value = (sizeof(*(T*)(0) < *(T*)(0)) != sizeof(no)) };
    };
}
template<typename T, bool>
struct CLASS_helper
{
    CLASS_helper(){/*some cool constructor*/}
};

template<typename T>
struct CLASS_helper<T, false>
{
    CLASS_helper()
    {
        std::string str("No operator< specified for ");
        str += typeid(T).name();
        str += ".\n";
        throw std::logic_error(str);
    };
};

template<typename T>
using CLASS = CLASS_helper<T, somenamespace::checker<T>::value>;

In order to use this you do

try
{
    CLASS<Foo> c;
}
catch(std::exception& e)
{
    std::cout << e.what();
}

Upvotes: 1

Columbo
Columbo

Reputation: 61009

Why throw an exception if you can static_assert at compile time?

template <typename T, typename=void>
struct LessThanComparable_ : std::false_type {};

template <typename T>
struct LessThanComparable_<T,
  decltype(void(std::declval<T>() < std::declval<T>()))>
    : std::true_type {};

template <typename T>
using LessThanComparable = LessThanComparable_<T>;

Example usage:

static_assert( LessThanComparable<std::string>::value, "" );
static_assert( LessThanComparable<int>::value, "" );
static_assert( !LessThanComparable<std::ostream>::value, "" );

Demo. Works equivalent with template parameters:

template <typename T>
struct MyTemplate
{
    static_assert( LessThanComparable<T>::value,
                   "Invalid type - must have less-than operator implemented" );
};

Upvotes: 4

Related Questions