c++ - 避免警告:对“计数”的操作可能未定义 [-Wsequence-point]
问题描述
我正在使用 Node.js N-API,并且正在制作一个小包装器,这将使导出 C++ 函数变得容易。
template<class T, class... Targs> napi_value Api::create(const char* name, T (* const cb)(Targs...))
{
// creates JavaScript function that will call cbProxy<> when called
return create(name, cbProxy<T, Targs...>, cb);
}
template<class T, class... Targs> napi_value Api::cbProxy(const napi_env env, const napi_callback_info info)
{
// number of arguments
size_t count = sizeof...(Targs);
ApiValue args[count];
T (* cb)(Targs...);
// retrieve arguments and callback
if (!Api::getParams(env, info, args, count, &cb))
return nullptr;
T ret = cb(Api::getValue<Targs>(&args[--count])...);
return Api(env).create(ret);
}
template<> bool Api::getValue(ApiValue* value)
{
return value->toBool();
}
template<> double Api::getValue(ApiValue* value)
{
return value->toDouble();
}
template<> int32_t Api::getValue(ApiValue* value)
{
return value->toInt32();
}
这个想法是调用api.create("TestFunction", testFn);
which 将返回一个 JS 函数。
当它被调用时,它将调用Api::cbProxy<>
将 JS 参数转换为等效的 C++ 类型,Api::getValue<T>()
并调用testFn
(cb)。
假设testFn
具有以下签名:int testFn(bool bVal, double dVal)
该行将T ret = cb(Api::getValue<Targs>(&args[--count])...);
扩展到
int ret = cb(Api::getValue<bool>(&args[--count]),
Api::getValue<double>(&args[--count]));
可以 100% 正常工作,但会触发编译器警告。我对 C++ 有点陌生,所以我正在寻找一种更好的方法来编写这个。
基本上我想一次遍历数组args
和类型参数列表Targs
。
只是为了澄清:--count
扩展函数调用中的 触发以下警告:
warning: operation on ‘count’ may be undefined [-Wsequence-point]
解决方案
我想问题在于
int ret = cb(Api::getValue<bool>(&args[--count]),
Api::getValue<double>(&args[--count]));
参数参数的评估顺序是依赖于实现的未定义行为(MM 校正),因此,count
从 开始2
,可以是
int ret = cb(Api::getValue<bool>(&args[1]),
Api::getValue<double>(&args[0]));
或者
int ret = cb(Api::getValue<bool>(&args[0]),
Api::getValue<double>(&args[1]));
为了确保 (the one) 的第一个索引args
是bool
并且1
第二个 (the double
one) is 0
,一种可能的方法是使用可变参数索引。
如果可以使用C++14,使用cbProxyHelper()
方法,可以尝试如下(注意:代码未测试)
template <typename T, typename ... Targs, std::size_t ... Is>
napi_value Api::cbProxyHelper (const napi_env env,
const napi_callback_info info,
std::index_sequence<Is...> const &)
{
// number of arguments
constexpr std::size_t count = sizeof...(Targs);
ApiValue args[count];
T (* cb)(Targs...);
// retrieve arguments and callback
if (!Api::getParams(env, info, args, count, &cb))
return nullptr;
T ret = cb(Api::getValue<Targs>(&args[count-1U-Is])...);
return Api(env).create(ret);
}
template <typename T, typename ... Targs>
napi_value Api::cbProxy (const napi_env env, const napi_callback_info info)
{ return cbProxyHelper(env, info, std::index_sequence_for<Targs...>{}); }
如果您使用的是 C++11,请进行模拟std::index_sequence
并且std::make_index_sequence
并不难。
推荐阅读
- python - 如何在 discord.py 中添加禁用命令
- ios - Xcode存档被缓存反应原生ios
- database - Redis对python应用的好处
- javascript - 数组状态上的 PureComponent 浅比较仍然重新呈现页面
- c# - 如何在 .Net 5.0 中配置 NodaTime 序列化
- angular - 如何修改ngif模板中的值?
- google-cloud-platform - GCP 组织政策限制列表
- 3d - 我想在 python 中的 3d 底图上绘制 2d 表面
- android - 空值检查运算符用于安全区域的空值
- python - Amazon S3 读取文件超时