clang / gcc类专业化不一致


9

我碰到这个问题,而试图专注tuple_size/ tuple_element自定义类在C ++ 17的结构结合。

下面的代码在GCC中编译,但在clang中不编译(两个主干版本,请参见下面的链接)。

#include <type_traits>

template<typename T, typename... Ts>
using sfinae_t = T;

template<typename T, bool... Bs>
using sfinae_v_t = sfinae_t<T, typename std::enable_if<Bs>::type...>;

template <typename T>
struct Test;

template <typename T>
struct Test<sfinae_v_t<T, std::is_integral_v<T>>> {};

void f() {
    Test<int> t;
}

https://godbolt.org/z/ztuRSq

这是clang提供的错误:

<source>:13:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

struct Test<sfinae_v_t<T, std::is_integral<T>::value>> {};

       ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

Compiler returned: 1

这是编译器中的错误,还是以上代码调用了一些UB?


3
这可以简化甚至更多
EVG

3
ICC和MSVC都同样无法编译。
ChrisMM

@Evg gcc编译它令人惊讶,因为它没有编译 ……
Max Langhof

1
FWIW如果我没有完全弄错的话,这应该是不正确的(出于同样的原因,是不正确的)。
Max Langhof

1
由于我们引用标准,因此我添加了language-lawyer标签。
Guillaume Racicot

Answers:


3

我在下面的内容(在OLD POST下)应该是正确的,但是实际的问题是SFINAE的使用不正确,因此我现在不确定这是gcc中的错误。

别名声明必须始终成功,不能在那里进行SFINAE,因为它不是类或函数的声明或特殊化(这很有意义,因为您不能特殊化别名)。如果别名声明不成功,则说明程序格式错误。因此,编译器可能会假设在您强制实例化这样的模板之前,别名声明不会成功。

因此,对于编译器来说,认为sfinae_v_t<T,...>always总是完全可以接受的T,因为当程序没有格式错误时,这将发生。因此,可以看到,在所有情况下,程序都不会格式错误,部分专业化不会专门化,因此它会告诉您这是格式错误的。(那是clang所做的)。

我不认为编译器会被迫这样做。如果没有,并且只是认为“好,sfinae_v_t是某种类型,无论如何。”,那么重新声明是不明显的。因此,我认为在实例化其中一个之前,不抛出错误没有任何错误。

但是当实例化它时,应该存在一个问题,即我们有重新声明,或者由于std::enable_if模板参数导致程序格式错误。GCC应该至少选择其中之一,但两者都不选。

这也绝对不适用于没有的更简单的示例std::enable_if。因此,我仍然认为这是GCC中的错误,但是我已经深深地迷糊了,无法再确定地说了。我只想说,有人应该将其报告为错误,并让gcc的人们考虑一下。

旧帖子

这是gcc中的错误。该标准为我们提供了在函数模板中转换类模板的规则。如果一个类模板的功能在部分功能模板排序中位于另一个类的前面,则它比另一个类更专业。

我在这里创建了函数,现在gcc声称调用它们是模棱两可的,因此还必须说,类模板是同等指定的。

注意:仔细阅读标准,我脑子里的编译器同意clang。


是否sfinae_v_t<T, std::is_integral_v<T>>sfinae_v_t<T, !std::is_integral_v<T>>视为相同类型?从语义上讲,不是。
ofo

@GuillaumeRacicot很可能,但是我想确切地理解为什么。例如,该标准还说 “在声明部分专业化时不能检查从属名称,但是在替换为部分专业化时将进行检查。” 难道不是因为sfinae_v_t<T>依赖于T而用部分专业化代替T后再确定它们是否相同T?在这种情况下,它们将是不一样的,因为任何一个都将是错误的格式。
ofo

@ofo我不得不说,我不确定。甚至考虑这两个问题也有点麻烦,因为它们中的一个永远不会成为类型,并且在非模板上下文中同时使用它们会由于导致编译错误enable_if_t。我对标准的最佳理解是,它们是否相同并不重要。对于部分排序,我们将始终将一个函数的模板参数形式与另一个函数的模板参数形式进行比较(即,该int函数已被替换),然后在其中一个函数中有一个realy类型,因此我们不必进行比较他们抽象。
n314159

1
深入挖掘,我从这里发现了一点。SFINAE应该可以与模板别名template<bool B, typename T> enable_if_t = typename enable_if<B, T>::type;一起正常工作,否则也不起作用。我将继续针对gcc提交该错误,但是不确定gcc是否在此处出错。谢谢。
ofo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.