重复: Is it possible to write a template to check for a function's existence?
我正在实现一个模板类,我想确保模板由具有operator<,operator ==等实现的类实例化。这样做的方法是什么?
答案 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