【发布时间】:2020-06-29 11:09:40
【问题描述】:
以下所有标准参考均指N4659: March 2017 post-Kona working draft/C++17 DIS。
考虑以下 sn-p:
#include <type_traits>
template <int N> struct num {};
template <typename> struct A;
// (1)
template <int N> struct A<num<N>> { using type = bool; };
// (2)
template <long N> struct A<num<N>> { using type = char; };
static_assert(!std::is_same_v<long, int>, "");
// (A)
static_assert(std::is_same_v<A<num<1>>::type, bool>, "");
int main() {}
(A) 处的 static_assert 对于 GCC 是成功的,但对于 Clang 是失败的:
error: static_assert failed due to requirement 'std::is_same_v<char, bool>' ""
本质上,GCC 选择了完美匹配的特化 (1),而 Clang 选择了特化 (2)。
同样,如果我们删除断言以及专业化(1):
template <int N> struct num {};
template <typename> struct A;
// (2)
template <long N> struct A<num<N>> { using type = char; };
int main() {
A<num<1>> a{};
(void)a;
}
然后 GCC 无法编译程序而 Clang 接受它。
海合会:
error: variable '`A<num<1> > a`' has initializer but incomplete type
此行为适用于各种 GCC 和 Clang 版本,以及超过这些版本的各种 C++ 语言级别(C++11、C++14、C++17、C++2a)。
问题
- 上面的第一个 sn-p 实际上是格式错误的(不需要诊断?),还是 GCC 或 Clang 错误?
我的猜测是这是格式错误的,但无法应用 [temp.class.spec] 的相关部分来拒绝它。也许[temp.class.spec]/8.1?
[temp.class.spec]/8.1 对应于专门化的非类型实参的模板形参的类型不应依赖于专门化的形参。 [ 示例:[...] — 结束示例 ]
【问题讨论】:
-
我相当肯定违反任何 [temp.class.spec]/8 项目符号都是可以诊断的。所以专业化本身会被标记。
-
@StoryTeller-UnslanderMonica 我同意,其中的示例甚至被归类为 OK 或 Error。
-
和wg21.link/cwg1647类似吗?
-
@LanguageLawyer 确实很相似,我们可以将a similar example 应用到 CWG Issue 1687 被 Clang 接受但被 GCC 拒绝的一个;正如问题报告中所写,“此示例的处理存在实现差异。”。这无法解释为什么 Clang 选择提升到
long专业化,其明显的“这是有效的 C++ 代码”解释(除非上面的示例实际上是格式错误的,不需要诊断,除了标准的歧义)完美匹配intsplzation。
标签: c++ language-lawyer