说:
int main()
{
int nX = 1 % 0; // <-- warning: divisioin by zero [-Wdiv-by-zero]
}
但
template<int N> struct A
{
std::array<int, N> m_Data;
int &Next()
{
return m_Data[(1 + 0) % N]; // <-- no warnings for N == 0
}
};
int main()
{
A<0> a; // nothing happens
}
为什么即使我使用"-Wall",GCC 也不会发出任何警告?谢谢大家!
为什么即使我使用"-Wall",GCC 也不会发出任何警告?
仅仅因为 gcc 的行为(或者更确切地说,g++; g++5.2 在我的情况)在这方面不一致。它似乎忘记了模板实例化上下文中的除以零诊断。在以下程序中:
int foo(int i) {
return i % 0;
}
template<typename T>
T bar(T i) {
return i % 0;
}
#include <iostream>
int main()
{
std::cout << foo(1) << std::endl;
std::cout << bar(1) << std::endl;
return 0;
}
函数模板的实例化bar<T>
由调用bar(1)
是一个与foo
相同的函数。然而:
$ g++-5 -c -std=c++11 -Wall -pedantic -Wextra main.cpp
main.cpp: In function ‘int foo(int)’:
main.cpp:2:14: warning: division by zero [-Wdiv-by-zero]
return i % 0;
^
G++只在foo
中诊断除以零,而
$ clang++-3.7 -c -std=c++11 -Wall -pedantic -Wextra main.cpp
main.cpp:2:14: warning: remainder by zero is undefined [-Wdivision-by-zero]
return i % 0;
^ ~
main.cpp:7:14: warning: remainder by zero is undefined [-Wdivision-by-zero]
return i % 0;
^ ~
main.cpp:16:18: note: in instantiation of function template specialization
'bar<int>' requested here
std::cout << bar(1) << std::endl;
clang++ 在 foo
和 bar<int>
中诊断除以零。
同样在程序中:
#include <array>
template<int N> struct A
{
std::array<int, N> m_Data;
int &Next()
{
return m_Data[(1 + 0) % N];
}
};
struct B
{
std::array<int, 0> m_Data;
int &Next()
{
return m_Data[(1 + 0) % 0];
}
};
#include <iostream>
int main()
{
A<0> a;
std::cout << a.Next() << std::endl;
B b;
std::cout << b.Next() << std::endl;
return 0;
}
类B
与类A<0>
相同,但G++只诊断:
main.cpp: In member function ‘int& B::Next()’:
main.cpp:32:31: warning: division by zero [-Wdiv-by-zero]
return m_Data[(1 + 0) % 0];
^
而 clang++ 诊断:
main.cpp:32:31: warning: remainder by zero is undefined [-Wdivision-by-zero]
return m_Data[(1 + 0) % 0];
^ ~
main.cpp:22:31: warning: remainder by zero is undefined [-Wdivision-by-zero]
return m_Data[(1 + 0) % N];
^ ~
main.cpp:43:20: note: in instantiation of member function 'A<0>::Next' requested here
std::cout << a.Next() << std::endl;
^
当然,一个符合要求的编译器不需要诊断除以零,即使可以。如果它可以这样做,它只是有帮助。
如果它有时在可以的时候这样做,有时不这样做,这是没有帮助的。然而您可能已经知道,编译时对属性的健全性检查模板参数可以使用语言和库的功能来实现,例如如static_assert
, std::enable_if
和蜥蜴。你示例模板可能需要 N
!= 0,如下所示:
template<int N> struct A
{
static_assert(N != 0,"N cannnot be 0 in struct A<N>");
std::array<int, N> m_Data;
int &Next()
{
return m_Data[(1 + 0) % N];
}
};