c++ - 尽可能在编译时强制执行函数契约
问题描述
(这个问题的灵感来自How can I generate a compiler error to prevent certain VALUE (not type) to go into the function?)
比方说,我们有一个单参数foo
,语义上定义为
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
上面的整个代码用于说明一个简单的想法 - 函数返回它自己的参数,除非参数等于 5,在这种情况下,行为是未定义的。
现在,挑战 - 以这样的方式修改函数,如果它的参数在编译时已知,则应该生成编译器诊断(警告或错误),如果不是,则行为在运行时保持未定义。解决方案可能依赖于编译器,只要它在四大编译器之一中可用。
以下是一些无法解决问题的潜在路线:
- 使函数成为将其参数作为模板参数的模板 - 这并不能解决问题,因为它使函数不符合运行时参数的条件
- 制作函数 a
constexpr
- 这并不能解决问题,因为即使编译器看到未定义的行为,它们也不会在我的测试中产生诊断 - 相反,gcc 会插入ud2
指令,这不是我想要的。
解决方案
constexpr
在常量表达式中使用时出现错误:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
我们无法知道参数值在编译类型中是已知的,但我们可以使用类型表示值std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
可能使用UDL和operator "" _c
to have 5_c
, 42_c
.
然后,添加重载:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
所以:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
正如我所说,参数在函数内部不知道是恒定的,并且is_constexpr
在标准中似乎不可能允许分派,但是一些编译器为此提供了内置的 ( __builtin_constant_p
),所以使用 MACRO,我们可以进行分派:
#define FOO(X) [&](){ \
if constexpr (__builtin_constant_p(X)) {\
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});\
} else {\
return foo(X); \
} \
}()
注意:不能foo(int_c<X>{})
直接使用,即使在 if constexpr 中,因为仍然有一些语法检查。
推荐阅读
- c# - 在用数据库中的数据填充组合框时,我创建了 SqlDataReader。我希望检索带有产品名称的列
- python - 如何在 Python 3 中将过滤器对象的元素获取到列表中?
- jquery - 3D 翻转卡在 Iphone 上没有旋转
- javascript - 数据未定义
- android - 尝试创建正确布局的问题
- regex - 尝试使用 RegEx 在文件中查找特定字符串
- c# - 视图没有被模型更新
- docker - 使用 Dockerfile 将文件从容器复制到主机
- angularjs - 从指令调用 $http 在 angularjs watch 中
- r - addMarkers 需要 R Shiny 中的非 NULL 经度/纬度值