ofo*_*ofo 9 c++ templates partial-specialization template-specialization language-lawyer
我在尝试为C++17 中的自定义类专门化tuple_size/tuple_element以进行结构化绑定时遇到了这个问题。
下面的代码在 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;
}
Run Code Online (Sandbox Code Playgroud)
这是 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
Run Code Online (Sandbox Code Playgroud)
这是编译器中的一个错误还是上面的代码调用了一些 UB?
我在下面(在OLD POST下)所说的在一定程度上应该是正确的,但实际的问题是 SFINAE 使用错误,因此我不再确定这是 gcc 中的错误。
别名声明必须始终成功,您不能在那里 SFINAE,因为它不是类或函数声明或特化(这是有道理的,因为您不能特化别名)。如果别名声明不成功,则程序格式错误。因此,编译器可能会认为,在您强制实例化这样的模板之前,它永远不会出现别名声明不成功的情况。
因此,编译器认为总是 是完全可以接受的sfinae_v_t<T,...>,T因为当程序不是格式错误时就会发生这种情况。因此,它将看到,在程序不是格式错误的所有情况下,部分特化不会特化,因此它会告诉您这是格式错误的。(这就是 clang 所做的)。
我不认为编译器被迫这样做。如果没有,并且只是认为“好吧,sfinae_v_t是某种类型,无论如何。”,那么这是一个重新声明并不明显。所以我认为,在我们实例化其中一个之前,不抛出错误并没有什么问题。
但是,当我们实例化它时,应该会出现以下问题:我们需要重新声明,或者由于 ,程序格式不正确std::enable_if,具体取决于模板参数。GCC 应该至少选择其中之一,但两者都没有。
这也绝对不适用于没有std::enable_if. 所以我仍然认为这是 GCC 中的一个错误,但我已经够心烦意乱了,我不能再肯定地说这一点了。我只想说,应该有人将其报告为错误,并让海湾合作委员会的人员考虑一下。
旧帖子
这是 gcc 中的一个错误。该标准为我们提供了在函数模板中转换类模板的规则。如果一个类模板的函数在部分函数模板排序中位于另一个类模板之前,则该类模板比另一个类模板更专业。
我在这里创建了这些函数,现在 gcc 声称调用它们是不明确的,因此它还必须说类模板是同等指定的。
注意:仔细阅读标准,我脑子里的编译器同意clang。