首页 > 解决方案 > 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 开始,这个错误仍然存​​在。

#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++c++11c++20sfinaec++-concepts

解决方案


在 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 代码上的行为也是一个错误。

有一个简单的解决方法。这些错误与解释名称有关,尤其是在不完整类的上下文中解释嵌套类。所以......将类型移动到命名空间范围:


推荐阅读