应根据C 标准进行以下代码编译
Should the following code compile according to C++ standard?
#include <type_traits>
template <typename T>
struct C;
template<typename T1, typename T2>
using first = T1;
template <typename T>
struct C<first<T, std::enable_if_t<std::is_same<T, int>::value>>>
{
};
int main ()
{
}
不同编译器编译的结果:
msvc:
错误C2753:'C':部分专业化无法匹配主模板的参数列表
GCC-4.9:
错误:部分专业化'c'不专业化任何模板参数
所有版本:
错误:类模板部分专业化并不专业化任何模板参数;要定义主模板,请删除模板参数列表
GCC-5 :成功编译
和其他我想指出的是:
template<typename T>
struct C<T>
{
};
成功未能由GCC编译。因此,似乎已经确定了我原始示例中的专业化是非平凡的。所以我的问题是 - 是否标准是否明确禁止这样的模式?
关键段落是[temp.class.spec]/(8.2),这要求部分专业化比主要模板更专业。Clang实际上抱怨的是,参数列表与主要模板相同:这已从第2033号问题中从[temp.class.spec]/(8.3)中删除(表明最近的要求是冗余的),因此hasn'hasn'T在Clang中实施。但是,鉴于它接受了您的片段,因此显然已经在海湾合作委员会中实施了。它甚至会编译以下内容,也许是出于同样的原因编译您的代码(也只能从版本5开始起作用):
template <typename T>
void f( C<T> ) {}
template <typename T>
void f( C<first<T, std::enable_if_t<std::is_same<T, int>::value>>> ) {}
即。它承认声明是不同的,因此必须已经实现了1980年问题的某些解决方案。但是,它并未发现第二个过载更加专业化(请参阅wandbox链接),但是,这是不一致的,因为它应该诊断出您的代码已经诊断出您的代码。根据(8.2)中的上述约束。
可以说,当前的措辞使您的示例的部分订购按要求的&Dagger; :[temp.deduct.type]/1提及从类型扣除时,
模板参数可以在几种不同的上下文中推导,但是在每种情况下,都将根据模板参数(调用
。P
)指定的类型与实际类型(称为A
)进行比较,并尝试尝试进行尝试。查找模板参数值[…]将使P
,替换为推论值(称其为推论A
),与A
兼容。
现在通过[temp.alias]/3,这意味着在部分订购步骤中,部分专业化函数的函数模板是参数模板,替换为 is_same
会产生false(因为公共库实现仅使用部分专业化必须失败),而enable_if
失败了。&Dagger; ,但是在一般情况下,这种语义并不令人满意,因为我们可以构建一个通常成功的条件,因此独特的合成类型可以满足它,并且推论成功了两种方式。
大概,最简单,最强大的解决方案是忽略部分订购期间被丢弃的参数(使您的示例不正确)。在这种情况下,也可以将自己定为实施行为(类似于第1157期):
template <typename...> struct C {};
template <typename T>
void f( C<T, int> ) = delete;
template <typename T>
void f( C<T, std::enable_if_t<sizeof(T) == sizeof(int), int>> ) {}
int main() {f<int>({});}
clang和GCC都诊断为调用已删除功能,即同意第一个超载比另一个过载更专业。#2的关键属性似乎是第二个模板参数取决于T
仅出现在非伪造的上下文中(如果我们在#1中将int
更改为T
,则没有任何更改)。因此,我们可以将废弃(和依赖的?)模板参数的存在作为打决我们:这样我们就不必推理合成价值的性质,这是现状,并且在您的情况下也获得了合理的行为,这将是很好的。
&Dagger; @t.c。提到,通过[temp.class.order]生成的模板当前将被解释为一个乘积声明的实体;再次,请参见第1980期。在这种情况下,这与标准人无关,因为措辞永远不会提到这些功能模板是宣布,更不用说在同一计划中了;它只是指定了它们,然后又回到功能模板的过程中。
&Dagger; 对执行此分析所需的深度实现并不完全清楚。问题1157证明了"正确"确定模板域是否是对方的适当子集需要的细节级别。实施部分命令成为这种复杂性既实用也不合理。但是,脚注部分只是表明该主题不一定被指定,而是有缺陷。
我认为您可以简化代码 - 这与type_traits无关。您将获得相同的结果:
template <typename T>
struct C;
template<typename T>
using first = T;
template <typename T>
struct C<first<T>> // OK only in 5.1
{
};
int main ()
{
}
在线编译器中检查(在5.1下编译,但使用5.2或4.9,这可能是一个错误)-https://godbolt.org/g/ivcbdm
我认为他们围绕模板功能移动了Int GCC 5,甚至可以创建两个相同类型的专业。它将进行编译,直到您尝试使用它为止。
template <typename T>
struct C;
template<typename T1, typename T2>
using first = T1;
template<typename T1, typename T2>
using second = T2;
template <typename T>
struct C<first<T, T>> // OK on 5.1+
{
};
template <typename T>
struct C<second<T, T>> // OK on 5.1+
{
};
int main ()
{
C<first<int, int>> dummy; // error: ambiguous template instantiation for 'struct C<int>'
}
https://godbolt.org/g/6ongdp
它可能以某种方式与对C 14变量模板的支持相关。https://isocpp.org/files/papers/n3651.pdf
- 如何修复sfml c++代码编译错误
- 尝试用java代码编译和运行c++代码
- 此代码编译良好,但文件未创建?请指出错误
- 为什么我的 BaseClass:Method 代码编译(带有单冒号)?
- 代码编译没有任何输出,入门程序
- 通过Python Distutils(用于Python C扩展)使用可重定位的设备代码编译CUDA代码
- 代码编译但不起作用!cmd窗口只是理想和理想,但什么也没发生
- 无法使用 g++ 使用C++代码编译 C 库
- 如何在Ubuntu中使用Visual Studio代码编译C++代码
- 推力+提升代码编译错误
- C++代码编译,但在 Zorin OS 上运行时显示错误
- 如何在使用模板时将 CPP 代码编译到库文件中
- 是否可以将Visual Studio 2017将C 代码编译到EXE以外的文件类型中
- 使用 Visual Studio for C++ 代码编译错误
- 使用 Android Studio 使用本机代码编译 apk 时,如何在链接处删除 libgnustl_static.
- 使用 Emscripten 将 OpenCV 代码编译C++ Javascript
- 将C 代码编译到独立应用程序.App
- 为什么此代码编译 (C++11) 而没有类型不匹配错误
- 重用编译器前端的结果,以加快多个配置/平台的C++代码编译
- 如何将C++11代码编译为网络汇编