zen*_*hoy 19 c++ gcc sfinae language-lawyer c++11
我最近将GCC升级到8.2,我的大多数SFINAE表达式都停止了工作.
以下是一些简化,但演示了问题:
#include <iostream>
#include <type_traits>
class Class {
public:
template <
typename U,
typename std::enable_if<
std::is_const<typename std::remove_reference<U>::type>::value, int
>::type...
>
void test() {
std::cout << "Constant" << std::endl;
}
template <
typename U,
typename std::enable_if<
!std::is_const<typename std::remove_reference<U>::type>::value, int
>::type...
>
void test() {
std::cout << "Mutable" << std::endl;
}
};
int main() {
Class c;
c.test<int &>();
c.test<int const &>();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
较旧版本的GCC(遗憾的是我不记得我之前安装的确切版本)以及Clang编译上面的代码就好了,但是GCC 8.2给出了一个错误说明:
: In function 'int main()':
:29:19: error: call of overloaded 'test()' is ambiguous
c.test();
^
:12:10: note: candidate: 'void Class::test() [with U = int&; typename std::enable_if::type>::value>::type ... = {}]'
void test() {
^~~~
:22:10: note: candidate: 'void Class::test() [with U = int&; typename std::enable_if::type>::value)>::type ... = {}]'
void test() {
^~~~
:30:25: error: call of overloaded 'test()' is ambiguous
c.test();
^
:12:10: note: candidate: 'void Class::test() [with U = const int&; typename std::enable_if::type>::value>::type ... = {}]'
void test() {
^~~~
:22:10: note: candidate: 'void Class::test() [with U = const int&; typename std::enable_if::type>::value)>::type ... = {}]'
void test() {
通常情况下,当不同的编译器和编译器版本以不同的方式处理相同的代码时,我假设我正在调用未定义的行为.标准对上述代码有什么看法?我究竟做错了什么?
注意:问题不在于解决这个问题的方法,有几个想到的.问题是为什么这不适用于GCC 8 - 标准是否未定义,或者它是编译器错误?
注意2:由于每个人都跳过默认void类型std::enable_if,我已经改变了要使用的问题int.问题仍然存在.
注3: 创建了GCC错误报告
这是我的看法.简而言之,铿锵是对的,而gcc则有回归.
我们根据[temp.deduct] p7:
替换发生在函数类型和模板参数声明中使用的所有类型和表达式中.[...]
这意味着无论包装是否为空,都必须进行替换.因为我们仍处于直接背景下,所以这是SFINAE能够做到的.
接下来我们知道一个variadic参数确实被认为是一个实际的模板参数; 来自[temp.variadic] p1
一个模板参数包是接受零个或多个模板参数模板参数.
和[temp.param] p2说明允许哪些非类型模板参数:
非类型模板参数应具有以下之一(可选的cv限定)类型:
一个文字的类型,具有强大的结构相等性([class.compare.default]),没有可变或易变的子对象,并且如果有一个默认的成员运算符<=>,那么它被声明为public,
左值参考类型,
包含占位符类型([dcl.spec.auto])或的类型
推导类类型的占位符([dcl.type.class.deduct]).
请注意,void不适合账单,您的代码(已发布)格式错误.
| 归档时间: |
|
| 查看次数: |
1216 次 |
| 最近记录: |