(此问题的灵感来自How can I generate a compilation 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,在这种情况下,行为是不确定的。
现在,挑战在于-以这种方式修改函数,如果在编译时知道其参数,则应生成编译器诊断(警告或错误),否则,行为在运行时仍未定义。解决方案可能取决于编译器,只要四大编译器之一都可用。
以下是一些无法解决问题的潜在路线:
constexpr
不能解决问题,因为即使编译器看到未定义的行为,它们也不会在我的测试中生成诊断信息,而是gcc插入了ud2
指令,不是我想要的。答案 0 :(得分:4)
在常量表达式中用于以下情况时,我在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
一起拥有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
seems not possible in standard不允许分派,但是某些编译器为此提供了内置函数(__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); \
} \
}()
注意:即使仍然使用constexpr,也不能直接使用foo(int_c<X>{})
,因为仍然需要进行一些语法检查。
答案 1 :(得分:2)
gcc / clang / intel编译器支持__builtin_constant_p,因此您可以使用类似的东西:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
这些语句产生编译时错误:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
所有其他字符-运行时段错误(如果未使用nullptr
,则为ub)
答案 2 :(得分:0)
这不是完美的,它要求我们在两个不同的地方使用参数,但它'有效':
server {
listen 80 default_server;
listen [::]:80;
root /var/www/html;
server_name example.com;
location /static {
alias /var/www/html/static/;
}
location / {
try_files $uri @wsgi;
}
location @wsgi {
proxy_pass http://unix:/tmp/gunicorn.sock;
include proxy_params;
}
location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
access_log off;
log_not_found off;
expires max;
}
}
我们可以这样称呼它:
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}