template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call(func);
}
在启用所有警告的情况下对此进行编译会产生:
$ g++ -std=c++14 -Wall foo.cxx
foo.cxx:2:6: warning: mangled name for ‘void call(Func) [with Func = void (*)() noexcept]’ will change in C++17 because the exception specification is part of a function type [-Wnoexcept-type]
void call(Func f)
^~~~
我应该怎么做这个警告?修复是什么?
答案 0 :(得分:19)
您可以对警告信息做几件事。
使用-Wno-noexcept-type
禁用它。在许多项目中,警告消息是无益的,因为结果对象不可能与另一个期望使用GCC的C ++ 17名称修改的对象链接。如果您没有使用不同的-std=
设置进行编译,并且您没有构建静态或共享库,其中违规功能是其公共接口的一部分,则可以安全地禁用警告消息。
使用-std=c++17
编译所有代码。警告消息将消失,因为该函数将使用新的受损名称。
创建函数static
。由于该函数不能再使用另一个对象文件引用该函数,因此不会显示警告消息。函数定义必须包含在使用它的所有编译单元中,但对于模板函数,例如在这个例子中,这是常见的。这也不适用于成员函数static
意味着别的东西。
调用函数模板时,指定模板参数显式给出不具有异常规范的兼容函数指针类型。例如call<void (*)()>(func)
。您也应该能够使用强制转换来执行此操作,但即使使用-std=c++17
不更改重整,GCC 7.2.0仍会生成警告。
当函数不是模板时,不要将noexcept
与函数类型中使用的任何函数指针类型一起使用。这和最后一点依赖于这样一个事实:只有非抛出函数指针类型才会导致命名修改更改,并且可以将非抛出函数指针分配(C ++ 11)或隐式转换(C ++ 17)到可能抛出函数指针。
答案 1 :(得分:3)
我赞成罗斯对call<void (*)()>(func)
解决方案的回答。它明确告诉编译器您希望为非noexcept
函数类型实例化模板,并保证您的代码在C ++ 17中的运行方式与在C ++ 14中完全相同。
更多选择是:
(1)将noexcept
函数包装在lambda中(不是noexcept
):
template <class Func>
void call(Func f)
{
f();
}
void func() noexcept { }
int main()
{
call([]() { func(); });
}
(2)创建一个没有noexcept
的单独包装函数。这最初是打字更多,但如果你有多个呼叫站点,它可以节省整体打字。这是最初提示我提交GCC错误的代码中的what I ended up doing。
答案 2 :(得分:1)
除了已经说过的话,我还找到了另一种方法来消除GCC 7中的此警告。显然,只有当call()
的第一个实例涉及{{1}时,GCC才会生成此警告。 }。因此,一种解决方案是首先使用非noexcept
函数实例化call()
。
此技巧还可以:
noexcept
P.S。在这种情况下,GCC 8.2.1不会报告警告。
答案 3 :(得分:0)
他们警告你的问题是,在C ++ 14中,这将起作用:
void call(void (*f)())
{
f();
}
void func() noexcept {}
int main(int argc, char* argv[])
{
call(&func);
return 0;
}
但在C ++ 17中,您需要将call
的声明更改为:
void call(void (*f)() noexcept)
{
f();
}
由于您已将call
定义为模板,因此您无需担心此问题。尽管如此,它可能会导致您出现问题,因为推断类型正在发生变化,而这种情况通常不会发生。
例如,此代码将在C ++ 14中编译,但不在C ++ 17中编译:
void foo() noexcept {}
void bar() {}
template <typename F>
void call(bool b, F f1, F f2)
{
if (b)
f1();
else
f2();
}
void foobar(bool b)
{
call(b, &foo, &bar);
}
在C ++ 14中,foo
和bar
的类型相同,但它们在C ++ 17中有所不同,这意味着模板解析将失败。带有标志-std=c++1z
的gcc 7.2中的错误消息是:
note: template argument deduction/substitution failed:
note: deduced conflicting types for parameter 'F' ('void (*)() noexcept' and 'void (*)()')
在您给出的示例中,没有问题,在C ++ 14或C ++ 17模式下编译时不会出现问题。如果代码比这里的示例更复杂(例如,类似于我上面给出的示例),您可能会遇到一些编译器问题。看来你有一个最近的编译器;尝试使用-std=c++1z
进行编译,看看是否有警告或错误。