成员函数检查:用c++ 11特性实现编译时检查
Member Function checking: Implement compilation-time checkings with C++11 features
我读到c++ 11有足够的静态检查(编译时),以实现c++ 11中应该是概念检查的很大一部分(已删除)。(我在最近一个关于概念删除的问题的评论中看到了这一点…
下面的c++ 03代码只检查类中成员函数的存在(我的模板类想要在其上工作)。下面是要搜索的4个成员函数,我总是使用相同的模式:
- 一个typedef定义函数原型的typedef
- 对static_cast的调用,如果typename TExtension没有定义这样的成员函数,或者如果它具有不同的原型,则会中断编译
代码如下:
template <typename TExtension>
class
{
...
void checkTemplateConcept()
{
typedef unsigned long (TExtension::*memberfunctionRequestedId)();
static_cast<memberfunctionRequestedId>(&TExtension::getRequestId);
typedef eDirection (TExtension::*memberfunctionDirection)();
static_cast<memberfunctionDirection>(&TExtension::getDirection);
typedef eDriveWay (TExtension::*memberfunctionDriveWay)();
static_cast<memberfunctionDriveWay>(&TExtension::getDriveWay);
typedef unsigned long (TExtension::*memberfunctionCycleId)();
static_cast<memberfunctionCycleId>(&TExtension::getCycleId);
}
}
这是在我的代码的某些部分,但它完全基于 c++ 03。我很乐意重写它,使用那些新的c++ 11特性…这里应该用什么呢?
在c++ 11中,您可以让编译器打印static_assert
的正确错误消息:
typedef unsigned long (TExtension::*required_type)();
typedef decltype(&TExtension::getRequestId) actual_type;
static_assert(std::is_same<required_type, actual_type>::value,
"The type of getRequestId must be unsigned long (C::*)()");
现在,如果成员函数的类型不匹配,编译器将打印这条有用的信息:
"The type of getRequestId must be unsigned long (C::*)()"
如果你愿意,你可以让它更具描述性。: -)
是的,在c++ 11中,SFINAE被扩展到表达式,所以你可以定义一个像is_t_extension
这样的trait来检测成员函数的存在,像这样:
template<class... T>
struct holder
{
typedef void type;
};
template<class T, class=void>
struct is_t_extension
: std::false_type
{};
template<class T, class=void>
struct is_t_extension<T, typename holder<
decltype(std::declval<T>().getRequestId),
decltype(std::declval<T>().getDirection),
decltype(std::declval<T>().getDriveWay),
decltype(std::declval<T>().getCycleId)
>::type>
: std::true_type
{};
现在这只是检查它们的存在。通过一些工作,您可以扩展上面的代码来检测有效的签名,或者您可以使用Tick库来编写trait,这样看起来干净多了:
TICK_TRAIT(is_t_extenstion)
{
template<class T>
auto requires_(T&& x) -> TICK_VALID(
returns<unsigned long>(x.getRequestId),
returns<eDirection>(x.getDirection),
returns<eDriveWay>(x.getDriveWay),
returns<unsigned long>(x.getCycleId)
);
};
然后在你的类你可以使用static_assert
报告错误:
template <typename TExtension>
class foo
{
static_assert(is_t_extension<TExtension>(), "Not a TExtension");
};
或者,如果您想允许专门化,您可以使用TICK_CLASS_REQUIRES
:
template <typename TExtension, class=void>
class foo;
template <typename TExtension>
class foo<TExtension, TICK_CLASS_REQUIRES(is_t_extension<TExtension>())>
{
...
};
相关文章:
- 如何实现自定义匹配器以检查 Catch2 中的对象相等性
- 对派生自同一基类的类实现冲突检查
- 实现编译检查以避免C++嵌套范围
- 十进制到二进制的实现不能完全适用于我大学的检查器。问题或提示可能是什么
- 如何检查 CNG Windows API 是否返回符合 FIPS 的算法实现
- 检查实现哪些基类
- 什么更有效率?在重载函数中或通过在基类函数中检查对象类型来实现
- C 混合蛋白,检查模板类型是否实现了某些混合蛋白
- 是否有任何类型安全的、编译时检查的 printf 的实现
- OmNET++动态检查NED模块是否实现了接口
- 如何实现更快的状态检查功能?蟒
- 如何检查是否实现了每个声明的类函数
- 我的双重检查锁定模式实现是否正确?
- 可以视觉C 检查不匹配的原型和实现
- 在C++中检查队列实现时出错
- C++ 在运行时检查对象是否实现接口
- 通过双重检查锁定模式实现call_once
- 使用较旧的C++实现在编译时检查一些编译时定义
- 在我的解释器上为脚本代码实现语法检查器的最佳方式是什么
- 实现编译时机制检查字符串的唯一性