如何检查是否为C ++中的模板定义了特定的运算符?

时间:2014-11-29 15:52:54

标签: c++ templates sfinae

我希望在没有将小于(<)运算符定义的类型传递给'myclass'时抛出异常。我添加了一些示例代码来帮助解释我想要做的事情。

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;
}

未来观众的注意事项:Nacl对问题的回答解决了问题,Columbo提供了更优雅的解决方案。

2 个答案:

答案 0 :(得分:4)

如果在编译时可以static_assert,为什么要抛出异常?

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>;

使用示例:

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

Demo。与模板参数等效的工作:

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

答案 1 :(得分:1)

这没用。实际上没有用于检查异常的用例,因为它们在运行时抛出,模板在编译时工作。使用Columbo提到的static_assert

但你可以这样做:

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>;

为了使用它,你可以

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