You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何含std::array成员的类默认太空船运算符被删除?

类成员含std::array时默认operator<=>被隐式删除的问题分析

问题重现

以下代码在Apple Clang 14.x、Clang 15.x中无法编译:

#include <array>
#include <compare>

struct test
{
    std::array<std::int64_t, 1> coords;
    auto operator<=>(const test&) const = default;
};

void test_f() {
    test c1{1}, c2{2};
    auto t1 = (c1 <= c2);
}

编译错误提示:

defaulted 'operator<=>' is implicitly deleted because there is no viable
three-way comparison function for member 'coords'

但单独使用std::array的比较逻辑却能正常通过编译:

void test_2() {
    std::array<std::int64_t, 1> coords{0};
    auto t1 = (coords <= coords);
}

问题原因

这是Clang对C++20标准中条件性生成成员函数的处理逻辑导致的:

  1. std::array的operator<=>是模板条件性提供的:只有当元素类型满足std::three_way_comparable要求时,才会实例化出这个三路比较运算符。
  2. 编译器尝试为test类默认生成operator<=>时,会检查成员coords是否存在可访问、非删除的三路比较运算符。但此时std::array<std::int64_t,1>的operator<=>还未被实例化,Clang会判定该成员没有符合要求的比较函数,因此将类的默认operator<=>标记为删除。
  3. 单独使用std::array的比较时,编译器会触发模板实例化流程,此时元素类型std::int64_t支持三路比较,operator<=>会被正确生成,因此代码可以正常编译。

解决方案

方案1:手动实现类的operator<=>

绕过默认生成逻辑,直接调用std::array的比较运算符:

struct test
{
    std::array<std::int64_t, 1> coords;
    auto operator<=>(const test& other) const {
        return coords <=> other.coords;
    }
};

这种方式会强制编译器实例化std::array的operator<=>,确保比较逻辑正常生效。

方案2:显式指定比较结果类型

如果需要保留默认生成的语义,可显式指定比较结果类型,帮助Clang正确推导:

struct test
{
    std::array<std::int64_t, 1> coords;
    std::strong_ordering operator<=>(const test&) const = default;
};

注意这种方式依赖于元素类型的比较结果类型匹配,对于std::int64_t来说,std::strong_ordering是正确的选择。

补充说明

这是Clang在处理模板类条件性成员函数时的行为差异,GCC在相同场景下可以正常编译默认生成的operator<=>。如果需要兼容更多编译器,推荐使用方案1的手动实现方式。

内容的提问来源于stack exchange,提问作者Raffi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 21:00:53