G++ C++17 类模板参数推导在非常特殊的情况下不起作用
g++ c++17 class template argument deduction not working in a very specific case
我有以下代码:
template <class T>
class lit {
public:
lit(T l) : val(l) {}
T val;
};
template <class T>
class cat {
public:
cat(lit<T> const& a, lit<T> const& b) : a(a), b(b) {}
lit<T> const& a;
lit<T> const& b;
};
template <class T>
cat<T> operator+(lit<T> const& a, lit<T> const& b) {
return cat(a, b);
}
int main() {
auto r1 = cat((lit ('b')), lit('d')); // compiles
auto r2 = (lit ('b')) + lit('d') ; // doesn't compile
auto r3 = lit ('b') + lit('d') ; // compiles
auto r4 = (lit ('b')) ; // compiles
auto r5 = (lit<char>('b')) + lit('d') ; // compiles
}
这使用 clang 编译得很好(正如我所期望的那样(,但 gcc 产生以下错误:
prog.cc: In function 'int main()':
prog.cc:23:20: error: missing template arguments after 'lit'
auto r2 = (lit ('b')) + lit('d') ; // doesn't compile
^~~
prog.cc:2:7: note: 'template<class T> class lit' declared here
class lit : public ExpressionBuilder<T> {
^~~
似乎无法仅在一种非常特殊的情况下(r2
(从构造函数中找出类模板的推导。我假设 gcc 是错误的,但有人可以解释为什么它只会在这种非常特殊的情况下失败吗?
此处的示例:https://wandbox.org/permlink/jQCOhXFFQekS17Y1
这是C++17 中的一个全新功能,因此在 GCC 中是全新的。您观察到的模式(或缺乏模式(看起来非常像编译器错误。它显然是随机触发的方式也符合这种模式。
对于 GCC 开发人员来说,进一步深入研究确切的方式和原因是一项乏味的工作,而不是堆栈溢出答案,因为它可能非常复杂......但现在正确的方法是提出一个错误并观察会发生什么。(OP 现在已经这样做了,作为错误 87709。
相关的例子已经存在于Bugzilla上。
编辑:此错误现已由 https://gcc.gnu.org/g:5f1a2cb9c2dc09eed53da5d5787d14bec700b10b 修复。
这就是我认为已经发生的事情:
有两种表达方式看起来相似,但含义却大不相同:
(type) + expr
(expr) + expr
第一个是 C 样式的强制转换表达式,它将一元表达式+ expr
转换为type
;第二个是执行加法的二进制表达式。
为了消除形式(something) + expr
表达式的歧义,GCC首先假定something
是一个类型,并进行试探性解析。如果成功,则整个表达式将被视为强制转换表达式;否则,something
将重新解析为表达式。
现在这就是我认为错误所在的地方:在试探性解析期间,GCC 错误地认为类模板参数推导 (CTAD( 不会出现,因此它在 CTAD 出现时发出错误。但事实上,即使在这种情况下试探性解析肯定会失败,something
可能仍然是一个有效的函数式强制转换表达式,因此重新解析可能会成功。
对于cat((lit('b')), lit('d'))
、lit('b') + lit('d')
和(lit('b'))
,GCC 足够聪明,看到它们不能是 C 风格的强制转换表达式,所以它不做试探性解析。对于(lit<char>('b')) + lit('d')
,lit<char>('b')
没有CTAD,所以也很好。
上述分析的证明:
如果将+
更改为/
(或除-
、*
或&
以外的大多数运算符(,则不会发生错误,因为(something) / expr
不能是有效的强制转换表达式。
sizeof(something)
中也存在类似的歧义(可能是sizeof(type)
或sizeof(expr)
(,并且正如预期的那样,sizeof(lit(0))
触发类似的错误。
- 我的神经网络不起作用 [XOR 问题]
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- C++为什么尽管我调用了void函数,它却不起作用
- 为什么在保护模式下继承升级不起作用
- 循环在计数器中不起作用
- 在其他文件中创建类时在 c++ 项目中不起作用
- Visual studio代码重构似乎不起作用(例如,重命名符号-f2)
- 为什么二进制搜索在我的测试中不起作用
- 我的代码中有错误吗?使用BGI图形的C++代码对我不起作用
- 为什么 const std::p air<K,V>& 在 std::map 上基于范围的 for 循环不起作用?
- 带有指定长度字符* 参数的 std::regex_search 在 VS2017 中不起作用?
- Bjarne Stroustrup Book - std_lib_facilities.h - 不起作用(未知类型名称)
- 为什么简单的算术减法在"if"条件下不起作用?
- 为什么Stroustup书中的has_f不起作用
- 你能检查一下为什么在这个代码中从链接列表中删除项目不起作用吗
- 嵌套While循环不起作用(C++问题)
- C++Matching Brackets 2解决方案不起作用
- G++ C++17 类模板参数推导在非常特殊的情况下不起作用
- 非常非常基本:为什么我的makefile不起作用