用c+编写和检查自己的概念+; 我正在编写一个只使用模板的头文件C++库。现在,我想添加一些概念检查,以处理在模板参数中使用不正确类型时引发的编译时错误
例如,我需要能够指向单个对象的类指针对象(如std::shared_ptr)、能够指向数组(通过操作符[])但不能与指针算法一起使用的类指针对象(如std::unique_ptr)以及能够与指针算法一起使用的指针等概念 因为概念仍然不是标准的,编译器也不支持,所以我需要自己实现它。我知道Boost概念库,但出于某种原因,我不想将其添加到依赖项中用c+编写和检查自己的概念+; 我正在编写一个只使用模板的头文件C++库。现在,我想添加一些概念检查,以处理在模板参数中使用不正确类型时引发的编译时错误,c++,boost,template-meta-programming,c++-concepts,C++,Boost,Template Meta Programming,C++ Concepts,例如,我需要能够指向单个对象的类指针对象(如std::shared_ptr)、能够指向数组(通过操作符[])但不能与指针算法一起使用的类指针对象(如std::unique_ptr)以及能够与指针算法一起使用的指针等概念 因为概念仍然不是标准的,编译器也不支持,所以我需要自己实现它。我知道Boost概念库,但出于某种原因,我不想将其添加到依赖项中 所以问题是,如何实现某些类型需求的检查?它是如何在Boost中实现的?在这种情况下,什么技术是常见的?自从我仍然使用C++11以来,我自己也做过一些类似
所以问题是,如何实现某些类型需求的检查?它是如何在Boost中实现的?在这种情况下,什么技术是常见的?自从我仍然使用C++11以来,我自己也做过一些类似的事情。基本上,这样做的方法是大量使用SFINAE并熟悉所有这些内容: 概念检查中最重要的是
enable\u if
:如果第一个模板参数为true
,则该模板提供给定的返回类型,如果该参数为false
,则会导致替换失败:
//this one gets called only for pointers
template <typename T>
typename enable_if<is_pointer<T>::value, bool>::type do_stuff(T) {}
//this one gets called only for non-pointers
template <typename T>
typename enable_if<not is_pointer<T>::value, bool>::type do_stuff(T) {}
现在,让我们来看看更难的部分:定义自己的概念,比如模板。如果可能的话,最好的方法就是根据上面链接中已经存在的标准编写它们。但是,有时您需要检查那里不可用的东西,例如,特定操作的可用性。在这种情况下,SFINAE是您的朋友:
template <typename T>
class is_equality_comparable {
template <typename U> static auto check(const U& u) -> typename std::conditional<
std::is_convertible<decltype(u == u), bool>::value,
std::true_type, std::false_type>::type;
static std::false_type check(...);
public:
static constexpr bool value = decltype(check(std::declval<T>()))::value;
};
模板
阶级是平等的{
模板静态自动检查(常量U&U)->typename std::conditional<
std::是否可转换::值,
std::true\u type,std::false\u type>::type;
静态标准::假_类型检查(…);
公众:
静态constexpr bool value=decltype(检查(std::declval())::value;
};
这将检查特定类型是否定义了相等运算符(operator==
),以及是否返回可以用作bool
的内容。但是,它是如何实现的,需要做一些解释:这个类所做的主要工作是定义一个从未调用过的check
方法,并通过计算check
的返回类型来生成正确的值。在底部,该类只是这样做的:当使用类型为T
的虚值调用时,它确定check
的返回类型(通过declval
生成,以避免依赖构造函数)。为了使其正常工作,提供了两个check
重载:第一个重载是模板化的,第二个重载使用..
符号,以接受任何参数,并具有比第一个重载更低的选择优先级。第一个重载使用一个后缀返回类型,这样它就可以引用它的参数(这使代码更干净),并根据操作符==
是否正确返回可以用作bool
的内容,使用conditional
在true\u类型
和false\u类型
之间进行选择。如果操作符==
不存在,第一个重载将导致替换失败,SFINAE将确保从可能的重载列表中悄悄地丢弃它,这意味着对检查的假设调用将返回到第二个重载,该重载只返回false\u type
当然,这只是我做这件事的方式;这是一种有效的方法,但我不确定Boost是这样做的,还是其他人是这样做的。如果你能够使用一个更新的C++版本,并支持实际的概念,那么你应该明确地使用它:在其他一些好的特性中,如果你做了错误的事情,你就可以得到可理解的错误信息,这不一定是你从上面提到的方法中得到的东西。最后,如果您真的决定做这样的事情,那么严格的测试是至关重要的:当您的类已经在代码中的其他地方使用时,很容易出错,并且很难找出如何修复它。自从我仍然使用C++11以来,我自己也做了一些类似的事情。基本上,这样做的方法是大量使用SFINAE并熟悉所有这些内容:
概念检查中最重要的是enable\u if
:如果第一个模板参数为true
,则该模板提供给定的返回类型,如果该参数为false
,则会导致替换失败:
//this one gets called only for pointers
template <typename T>
typename enable_if<is_pointer<T>::value, bool>::type do_stuff(T) {}
//this one gets called only for non-pointers
template <typename T>
typename enable_if<not is_pointer<T>::value, bool>::type do_stuff(T) {}
现在,让我们来看看更难的部分:定义自己的概念,比如模板。如果可能的话,最好的方法就是根据上面链接中已经存在的标准编写它们。但是,有时您需要检查那里不可用的东西,例如,特定操作的可用性。在这种情况下,SFINAE是您的朋友:
template <typename T>
class is_equality_comparable {
template <typename U> static auto check(const U& u) -> typename std::conditional<
std::is_convertible<decltype(u == u), bool>::value,
std::true_type, std::false_type>::type;
static std::false_type check(...);
public:
static constexpr bool value = decltype(check(std::declval<T>()))::value;
};
模板
阶级是平等的{
模板静态自动检查(常量U&U)->typename std::conditional<
std::是否可转换::值,
std::true\u type,std::false\u type>::type;
静态标准::假_类型检查(…);
公众:
静态constexpr bool value=decltype(检查(std::declval())::value;
};
这将检查特定类型是否定义了相等运算符(operator==
),以及是否返回可以用作bool
的内容。然而,它是如何做到的,需要一些解释:这个类所做的主要事情是定义一个从未被调用的check
方法,并通过计算ch来生成正确的值