gpt4 book ai didi

c++ - 下面的代码是否应该按照 C++ 标准编译?

转载 作者:IT老高 更新时间:2023-10-28 22:15:08 24 4
gpt4 key购买 nike

#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:

error C2753: 'C': partial specialization cannot match argument list for primary template

gcc-4.9:

error: partial specialization 'C' does not specialize any template arguments

clang 所有版本:

error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

gcc-5+:编译成功

另外,我想指出一些琐碎的特化,例如:

template<typename T>
struct C<T>
{
};

gcc 编译成功失败。因此,似乎发现我最初的示例中的特化并非易事。所以我的问题是 - C++ 标准是否明确禁止这样的模式?

最佳答案

关键段落是[temp.class.spec]/(8.2) ,这要求部分特化比主模板更特化。 Clang 实际上提示的是参数列表与主模板的相同:这已从 [temp.class.spec]/(8.3) 中删除。由 issue 2033 (声明该要求是多余的)最近,所以还没有在 Clang 中实现。但是,鉴于它接受您的代码段,它显然已在 GCC 中实现;它甚至compiles the following ,也许出于同样的原因,它会编译您的代码(它也只能从版本 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) 中的上述约束来诊断您的代码。

可以说,当前的措辞使您的示例的部分排序按预期工作:[temp.deduct.type]/1提到从类型推导中,

Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A), and an attempt is made to find template argument values […] that will make P, after substitution of the deduced values (call it the deduced A), compatible with A.

现在通过 [temp.alias]/3 ,这意味着在部分特化的函数模板是参数模板的部分排序步骤中,替换为 is_same 会产生错误(因为公共(public)库实现只使用必须失败的部分特化), enable_if 失败。 但是这种语义在一般情况下并不令人满意,因为我们可以构造一个通常成功的条件,因此唯一的合成类型满足它,并且推导双向成功。

大概,最简单和最强大的解决方案是在部分排序期间忽略丢弃的参数(使您的示例格式错误)。在这种情况下,人们也可以将自己定位于实现的行为(类似于问题 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>({});}

两者ClangGCC将此诊断为调用已删除的函数,即同意第一个重载比另一个重载更专业。 #2 的关键属性似乎是第二个模板参数是依赖的,但 T 仅出现在非推导上下文中(如果我们将 int 更改为 T 在 #1 中,没有任何变化)。所以我们可以使用丢弃的(和依赖的?)模板参数的存在作为决胜局:这样我们就不必推理合成值的性质,这是现状,并且在你的情况下也得到合理的行为,这将是格式良好的。


@T.C.提到通过 [temp.class.order] 生成的模板目前将被解释为一个多重声明的实体——再次,请参阅问题 1980。 .在这种情况下,这与标准语言没有直接关系,因为措辞从来没有提到这些函数模板是被声明的,更不用说在同一个程序中了;它只是指定它们,然后回退到函数模板的过程。

执行此分析所需的深度实现并不完全清楚。问题 1157演示“正确”确定模板的域是否是其他域的适当子集所需的详细程度。将部分排序实现得如此复杂既不实际也不合理。但是,脚注部分只是表明该主题不一定未指定,而是有缺陷。

关于c++ - 下面的代码是否应该按照 C++ 标准编译?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41143524/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com