确保c ++类具有某些成员函数

时间:2014-08-23 04:14:13

标签: c++ templates types

重复: Is it possible to write a template to check for a function's existence?

我正在实现一个模板类,我想确保模板由具有operator<,operator ==等实现的类实例化。这样做的方法是什么?

3 个答案:

答案 0 :(得分:1)

C ++模板具有duck typing之类的行为。如果它看起来像一只鸭子,像鸭子一样走路,像鸭子一样呱呱叫,那就是鸭子。基本上,如果您在模板参数的实例上使用运算符或调用函数,则该参数将需要覆盖该运算符或实现该方法。

答案 1 :(得分:1)

如前所述,如果您的C ++模板类使用模板参数的任何函数或成员,编译器将在编译期间检查实例化类型是否具有这些函数和成员。

如果您需要显式检查,可以使用boost::concept_check,此库允许您指定实例化类型需要满足的约束。

检查概念类的示例:

template <class X>
struct InputIterator
  : Assignable<X>, EqualityComparable<X>
{
 private:
    typedef std::iterator_traits<X> t;
 public:
    typedef typename t::value_type value_type;
    typedef typename t::difference_type difference_type;
    typedef typename t::reference reference;
    typedef typename t::pointer pointer;
    typedef typename t::iterator_category iterator_category;

    BOOST_CONCEPT_ASSERT((SignedInteger<difference_type>));
    BOOST_CONCEPT_ASSERT((Convertible<iterator_category, std::input_iterator_tag>));

    BOOST_CONCEPT_USAGE(InputIterator)
    {
        X j(i);             // require copy construction
        same_type(*i++,v);  // require postincrement-dereference returning value_type
        X& x = ++j;         // require preincrement returning X&
    }

 private:
    X i;
    value_type v;

    // Type deduction will fail unless the arguments have the same type.
    template <typename T>
    void same_type(T const&, T const&);
};

使用该概念的例子:

// In my library:
template <class It>
class generic_library_class
{
  BOOST_CONCEPT_ASSERT((InputIterator<It>));
  // ...
};

// In the user's code:  
class foo {
  //... 
};

int main() {
  generic_library_class<std::vector<char>::iterator> y;
  //... 
}

答案 2 :(得分:1)

C ++ 11提供了一个非常方便的运算符decltype(e),它允许查询表达式的结果类型,该表达式根本不在运行时计算,仅在编译时。

这与<type_traits>结合使用,可用于手写static_assert的模板助手:

#include <type_traits>

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

template <typename T>
struct is_equality_comparable<T,
        typename std::enable_if<
          std::is_convertible<decltype(std::declval<T&>() == std::declval<T&>())
          , bool>{}>::type
        > : std::true_type {};

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

template <typename T>
struct is_less_than_comparable<T,
        typename std::enable_if<
          std::is_convertible<decltype(std::declval<T&>() < std::declval<T&>())
          , bool>{}>::type
        > : std::true_type {};

也就是说,您可以在decltype(e)中放置任何表达式并检查它是否是例如可转换为布尔类型,就像std::declval<T&>() < std::declval<T&>()一样,可用性低于可比性。

现在,只要您想为模板的参数添加约束,只需在类声明中添加static_assert即可。

让我们首先定义一些将用于测试的类:

// sample equlity comparable type with **member** operator==
struct EqComparable
{
    bool operator==(const EqComparable& other)
    {
        return i == other.i;
    }

    int i;
};

// sample less-than comparable type with **global** operator<
struct LessThanComparable
{
    int i;
};

bool operator<(const LessThanComparable& lhs, const LessThanComparable& rhs)
{
    return lhs.i < rhs.i;
}

// sample class which is not comparable in any way
struct NotComparableAtAll
{
};

现在让我们对类应用约束:

// your template classes with constraints:

template <typename T>
class MustBeEqComparable
{
    static_assert(is_equality_comparable<T>::value,
                  "Type T is not equality comparable!");
};

template <typename T>
class MustBeLessThanComparable
{
    static_assert(is_less_than_comparable<T>::value,
                  "Type T is not less than comparable!");
};

现在让我们尝试实例化每个:

MustBeEqComparable<EqComparable> a;

MustBeEqComparable<NotComparableAtAll> b; // issues an error

MustBeLessThanComparable<LessThanComparable> c;

MustBeLessThanComparable<NotComparableAtAll> d; // issues an error

DEMO