c++ - C++ 概念/SFINAE:clang 和 MSVC/G++ 使用模板和概念/SFINAE 进行离线函数定义的不同结果
问题描述
我正在定义一个类的构造函数,该构造函数在概念或 SFINAE 的帮助下,受限于检查传入迭代器的底层类型与我的类中定义的 node_type 的类型等价性。
但是,尝试了一些与is_same<>, is_same_v<>, enable_if<>
, 和same_as<>
concept 的组合,离线定义将始终在至少一个主要编译器上产生编译时错误。目前,下面的代码片段在 MSVC/g++ 上没有看到错误,但 clang 抱怨,都使用最新版本(分别为 19.28、11.1、12.0)。谁能澄清这里有什么问题?谢谢。
编辑:
从 GCC 12 和 Clang 14 开始,这个错误仍然存在。
使用 C++20 在 Godbolt 上的代码如下,MSVC/g++ ok,clang 错误 https://godbolt.org/z/fdqEYxKh8
代码未在下面显示,但在 Godbolt 上使用 C++11 SFINAE、MSVC/clang ok、g++ 错误 https://godbolt.org/z/7nr7a8jY8
#include <stdio.h>
#include <iterator>
#include <array>
#include <concepts>
#include <cstdlib>
template <typename FPType, std::size_t N>
class PointND {
private:
std::array<FPType, N> coords_;
};
template <typename FPType, std::size_t N, typename ElemType>
class Tree {
public:
struct node_type {
PointND<FPType, N> key;
ElemType value;
};
template <std::random_access_iterator RAI>
requires std::same_as<typename std::iterator_traits<RAI>::value_type,
typename Tree<FPType, N, ElemType>::node_type>
Tree(RAI, RAI);
};
template <typename FPType, std::size_t N, typename ElemType>
template <std::random_access_iterator RAI>
requires std::same_as<typename std::iterator_traits<RAI>::value_type,
typename Tree<FPType, N, ElemType>::node_type>
Tree<FPType, N, ElemType>::Tree(RAI begin, RAI end) {
}
此行错误::45:30: 错误: 'Tree<FPType, N, ElemType>' 的行外定义与 'Tree<FPType, N, ElemType>' 中的任何声明都不匹配
Tree<FPType, N, ElemType>::Tree(RAI begin, RAI end) {
解决方案
在 C++11 示例中,add-fchecking
和 gcc 会说:
<source>:52:51: internal compiler error: canonical types differ for identical types 'std::enable_if<(std::is_same<typename std::iterator_traits<_InputIterator>::iterator_category, std::random_access_iterator_tag>::value && std::is_same<typename std::iterator_traits<_InputIterator>::value_type, typename Tree<FPType, N, ElemType>::node_type>::value), int>' and 'std::enable_if<(std::is_same<typename std::iterator_traits<_InputIterator>::iterator_category, std::random_access_iterator_tag>::value && std::is_same<typename std::iterator_traits<_InputIterator>::value_type, Tree<FPType, N, ElemType>::node_type>::value), int>'
52 | Tree<FPType, N, ElemType>::Tree(RAI begin, RAI end) {
| ^
...
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
gcc 无法编译这是一个编译器错误。
我怀疑但不能证明 clang 在 C++20 代码上的行为也是一个错误。
有一个简单的解决方法。这些错误与解释名称有关,尤其是在不完整类的上下文中解释嵌套类。所以......将类型移动到命名空间范围:
- https://godbolt.org/z/ch7s8nKxo (C++11)
- https://godbolt.org/z/T4cjb79zP (C++20)
推荐阅读
- javascript - 从另一个数组的匹配对象值创建一个数组
- cypress - 赛普拉斯:“任务”事件尚未在插件文件中注册。您必须在使用 cy.task() 之前注册它
- java - 从 hashmap 键集中用连字符分隔的字符串
- google-sheets - 我在谷歌表格中的最大值操作发生了什么?
- flutter - Firebase Flutter Web 身份验证持久性
- android - Android Composable - 在图像分析器中绘图
- asp.net-core - 如何使用 C# 在 ASP.NET Core 3.1 MVC 中显示长进程的进度条?
- python-3.x - Airflow 2.0.2 - Jinja2 顶级模板错误
- database - PG Restore 是不是恢复数据库触发器?
- spring-boot - 如何在使用 Java 11 的 Spring Boot Maven 应用程序中使用 https 集成 proguard?