【问题标题】:C++ Concepts/SFINAE: clang and MSVC/G++ different results for out of line function definition with template and Concept/SFINAEC++ 概念/SFINAE:clang 和 MSVC/G++ 使用模板和概念/SFINAE 进行离线函数定义的不同结果
【发布时间】:2021-08-30 01:21:50
【问题描述】:

我正在定义一个类的构造函数,该构造函数受限于检查传入迭代器的底层类型与我的类中定义的 node_type 的类型等价性,这需要借助概念或 SFINAE。

但是,尝试了一些与is_same<>, is_same_v<>, enable_if<>same_as<> 概念的组合,离线定义总是会在至少一个主要编译器上产生编译时错误。目前低于SN-P在MSVC / G ++上看到没有错误,但克朗抱怨,所有使用最新版本(分别为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 '的行外定义与''的任何声明不匹配

Tree<FPType, N, ElemType>::Tree(RAI begin, RAI end) {

【问题讨论】:

  • _Tp 使您的程序格式不正确。以_ 开头,然后为编译器保留一个大写字母only(和内置库)。 (你应该解决这个问题,但这不是你的编译器错误的触发器)
  • 为什么是 C++11 标签?
  • @ ennico因为我尝试了c ++ 11 enable_if >方式,clang将编译但msvc和g ++不会。 span>
  • @Yakk-AdamNevraumont,感谢您的建议,已在实施中修复。
  • @Nkk,我认为这不是使用该标签的理由。 enable_if 在 C++20 中仍然存在并且运行良好。我认为您应该删除标记,该标记显示将此标记用于必须编译为 C++11 的代码。是否需要编译为 C++11?如果没有,则删除标签。

标签: c++ c++11 c++20 sfinae c++-concepts


【解决方案1】:

在 C++11 示例中,添加 -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 代码上的行为也是一个错误。

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

【讨论】:

  • 将嵌套类移到外部是一个设计决策,会产生不良影响,而不是像命名别名这样的微不足道的改变。一个简单的例子,两个编译器都失败了,如果被证明,应该比仅仅解决方法更值得关注。但感谢您的意见。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-17
  • 1970-01-01
  • 2021-09-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多