-Werror是否会干扰模板的正确性和/或SFINAE



我觉得这是一个愚蠢的问题,我想答案是简单的"不",尽管除了寻求你的帮助,我不知道如何确定。。。

-Werror是否会干扰模板的正确性(不确定什么是正确的术语,请参阅下面的示例(和/或SFINAE

考虑一下这个简单的人为例子:

template <typename T>
void foo() {
int a;
}
int main() {
//int a; // error: unused variable 'a' [-Werror=unused-variable]
}

使用-Werror编译时,取消对main中的行的注释会导致错误。我知道编译器应该为任何模板参数(即使没有实例化(都有错误的模板生成错误。这里的情况并非如此。当我实例化模板时,我只会在这里看到错误(当然这实际上只是一个警告(。

为什么我问这个问题:我习惯于总是使用-Werror进行编译,因此我对什么是警告,什么是错误的看法在某些方面有点模糊。现在,对于模板,尤其是SFINAE,如果某个东西只是一个警告或真正的错误,它确实会产生很大的影响。

我知道编译器应该为任何模板参数(即使没有实例化(错误的模板生成错误。

但事实并非如此。如果无法为模板生成实例化,则程序格式错误,不需要诊断(1(。因此,无论你是遇到错误还是"成功"编译,程序都是格式错误的

从另一个角度来看,编译器不能允许由警告引发的错误影响SFINAE,因为这可能会改变有效程序的语义,从而使编译器不一致。因此,如果编译器想将警告诊断为错误,则必须停止编译,而不是引入替换失败。

换句话说,-Werror可以使编译器拒绝一个格式良好的程序(毕竟这是它的预期目的(,但如果它改变了一个程序的语义,那将是一个编译器错误。


(1(报价C++17(N4659(,[temp.res]17.6/8:

程序格式错误,无需诊断,如果:

  • 不能为模板生成有效的专门化。。。并且模板未实例化,或者

虽然这在很大程度上是一个实现质量问题,但-Werror确实(而且确实(会干扰SFINAE。下面是一个更复杂的例子来测试它:

#include <type_traits>
template <typename T>
constexpr bool foo() {
if (false) {
T a;
}
return false;
}
template<typename T, typename = void> struct Check {};
template<typename T> struct Check<T, std::enable_if_t<foo<T>()>> {};
int main() {
Check<int> c;
}

T a;可以触发该警告(和错误(,即使分支是死的(它是故意死的,所以foo是一个constexpr函数,而与T无关(。现在,根据标准本身,这是一个形式良好的程序。

但是,由于Clang和GCC在那里导致了一个错误,并且该错误是在Check专门化的非即时上下文中发生的,所以我们会得到一个硬错误。尽管根据标准本身,由于仅在直接上下文中的替换失败,这应该只是回到主模板。

最新更新