我浪费了无数个小时来查明 gcc 的问题。我想用另一个编译器测试我们的代码库,以寻找更多 Clang 的警告。可能错过了。令我震惊的是,由于模板参数推导失败,几乎一半的项目停止编译。在这里,我试图将我的案例简化为最简单的代码。
#include <type_traits>
struct Foo
{ };
// This is a template function declaration, where second template argument declared without a default
template <typename T, typename>
void foo(const Foo & foo, T t);
// This is a template function definition; second template argument now has a default declared
template <typename T, typename = typename std::enable_if<1>::type>
void foo(const Foo & foo, T t)
{
}
int main(int argc, char ** argv)
{
foo(Foo{}, 1);
return 0;
}
忽略 1
在 std::enable_if<1>
.显然,它是一个常数值,只是为了在无关紧要的情况下不使事情复杂化。
这段代码编译[1]使用 clang(3.4 到 4.0)、icc(16、17)、Visual C++(19.00.23506)。基本上,我找不到任何其他 c++11 编译器,除了 gcc(4.8 到 7.1),不编译这段代码。
问题是,这里谁对谁错? gcc 是否符合标准?
显然这不是一个关键问题。我可以轻松移动std::enable_if
到声明。唯一的受害者将是美学。但是能够隐藏一个丑陋的 100 个字符长度是很好的 std::enable_if
在实现中与库函数的用户没有直接关系的一段代码。
godbolt.org 上的实时示例.
最佳答案
标准内容([1] 第 350 页):
The set of default template-arguments available for use with a template declaration or definition is obtained by merging the default arguments from the definition (if in scope) and all declarations in scope in the same way default function arguments are (8.3.6). [ Example:
template<class T1, class T2 = int> class A; template<class T1 = int, class T2> class A; is equivalent to template<class T1 = int, class T2 = int> class A;
— end example ]
所以 GCC 在这里是错误的。它会忽略声明中的默认模板参数。
不是所有的声明,只有函数模板声明。类模板声明没问题:
#include <type_traits>
template <typename T, typename>
struct Foo;
template <typename T, typename = typename std::enable_if<1>::type>
struct Foo
{
T t;
};
int main()
{
Foo<int> foo;
return 0;
}
godbolt.org 上的实时示例
这可能是由于非默认参数的推断方式的性质。在函数模板中,它们是从函数参数中扣除的。在类模板中,我们必须明确指定它们。
不管怎样,我已经创建了一个 bug report .
关于c++ - 所有版本的 GCC 都在使用在定义中具有默认类型的模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43993162/