使用声明:gcc 和 clang 的另一个错误?
using declaration: one more bug of gcc and clang?
为什么 gcc HEAD 10.0.0 20190
和 Clang HEAD 9.0.0
都拒绝这个程序?
#include <iostream>
void g( int x )
{
std::cout << "Hello g( " << x << " )\n";
}
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
namespace N
{
using ::g;
}
void g( int x = 20 );
template <int N = 10>
void g();
int main()
{
N::g();
N::g<>();
}
例如gcc
发出错误
prog.cc: In function 'int main()':
prog.cc:27:11: error: no matching function for call to 'g()'
27 | N::g<>();
| ^
prog.cc:9:6: note: candidate: 'template<int N> void g()'
9 | void g()
| ^
prog.cc:9:6: note: template argument deduction/substitution failed:
prog.cc:27:11: note: couldn't deduce template parameter 'N'
27 | N::g<>();
| ^
虽然根据 C++ 20(和 17)标准(9.8 using 声明)
11 [Note: For a using-declaration whose nested-name-specifier names a
namespace, members added to the namespace after the using-declaration
are not in the set of introduced declarations, so they are not
considered when a use of the name is made. Thus, additional overloads
added after the using-declaration are ignored, but default function
arguments (9.2.3.6), default template arguments (13.1), and template
specializations (13.6.5, 13.8.3) are considered. — end note]
根据我对标准的阅读,我认为这是一个错误。
我认为问题在于您在 g<int>
模板函数定义期间隐式声明后重新声明它。
这个最小化的例子也编译失败。注意不涉及名称空间:
#include <iostream>
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
// redeclaration
template <int N = 10>
void g();
int main()
{
g<>();
}
而这个编译:
#include <iostream>
// declaration
template <int N = 10>
void g();
// definition
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
int main()
{
g<>();
}
此问题是 Core issue 1907 的主题。目前的方向是将此类病例视为病态,无需诊断。
事实证明,一些实现在 "per-entity" 的基础上跟踪默认参数(因此很难不考虑在以后的重新声明中添加的默认参数),而其他实现在 [=16] 上跟踪它们=] 基础(所以很难让他们考虑这样的默认参数)。 CWG 决定通过对依赖于此类 IFNDR 的代码进行分类来适应这两种实施策略。
为什么 gcc HEAD 10.0.0 20190
和 Clang HEAD 9.0.0
都拒绝这个程序?
#include <iostream>
void g( int x )
{
std::cout << "Hello g( " << x << " )\n";
}
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
namespace N
{
using ::g;
}
void g( int x = 20 );
template <int N = 10>
void g();
int main()
{
N::g();
N::g<>();
}
例如gcc
发出错误
prog.cc: In function 'int main()':
prog.cc:27:11: error: no matching function for call to 'g()'
27 | N::g<>();
| ^
prog.cc:9:6: note: candidate: 'template<int N> void g()'
9 | void g()
| ^
prog.cc:9:6: note: template argument deduction/substitution failed:
prog.cc:27:11: note: couldn't deduce template parameter 'N'
27 | N::g<>();
| ^
虽然根据 C++ 20(和 17)标准(9.8 using 声明)
11 [Note: For a using-declaration whose nested-name-specifier names a namespace, members added to the namespace after the using-declaration are not in the set of introduced declarations, so they are not considered when a use of the name is made. Thus, additional overloads added after the using-declaration are ignored, but default function arguments (9.2.3.6), default template arguments (13.1), and template specializations (13.6.5, 13.8.3) are considered. — end note]
根据我对标准的阅读,我认为这是一个错误。
我认为问题在于您在 g<int>
模板函数定义期间隐式声明后重新声明它。
这个最小化的例子也编译失败。注意不涉及名称空间:
#include <iostream>
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
// redeclaration
template <int N = 10>
void g();
int main()
{
g<>();
}
而这个编译:
#include <iostream>
// declaration
template <int N = 10>
void g();
// definition
template <int N>
void g()
{
std::cout << "Hello g<N>( " << N << " )\n";
}
int main()
{
g<>();
}
此问题是 Core issue 1907 的主题。目前的方向是将此类病例视为病态,无需诊断。
事实证明,一些实现在 "per-entity" 的基础上跟踪默认参数(因此很难不考虑在以后的重新声明中添加的默认参数),而其他实现在 [=16] 上跟踪它们=] 基础(所以很难让他们考虑这样的默认参数)。 CWG 决定通过对依赖于此类 IFNDR 的代码进行分类来适应这两种实施策略。