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

如何准确检测包含boost::multiindex的类是否具备可比较性?

问题

我写了一个模板函数compare,意图检测类是否具备可比较性,仅在可比较时执行比较逻辑:

template <typename T>
int compare(const T& a, const T& b)
{
    if constexpr (std::three_way_comparable<T>) {
        std::cerr << "comparable " << typeid(T).name() << "\n";
        if (a == b) {
            return 0;
        }
        if (a < b) {
            return -1;
        }
        if (a > b) {
            return 1;
        }
    } else {        
        std::cerr << "not comparable " << typeid(T).name() << "\n";
    }
    return 0;
}

该函数在简单结构体场景下运行正常:

struct CompStruct
{
    int         a {};
    std::string b;
    auto        operator<=>(const CompStruct&) const = default;
};

struct UncompStruct
{
    int         a {};
    std::string b;
    auto        operator<=>(const UncompStruct&) const = delete;
};

CompStruct cs_a, cs_b;
compare(cs_a, cs_b); // 输出"comparable"

UncompStruct ucs_a, ucs_b;
compare(ucs_a, ucs_b); // 输出"not comparable"

但当使用嵌套了不可比较内部类型的boost::multiindex时,代码编译失败:

namespace bmi = boost::multi_index;
using MultiIndex = bmi::multi_index_container<
    UncompStruct, bmi::indexed_by<bmi::random_access<>>>;
    
struct bad_type : std::map<std::string, MultiIndex>
{};

bad_type bt_a;
bad_type bt_b;
compare(bt_a, bt_b);  // 编译失败

将multiindex内部的UncompStruct替换为CompStruct时则编译正常。现在需要解决:如何真正检测一个类是否具备可比较性?

解决方案

问题根源在于std::three_way_comparable仅检查类型是否存在符合要求的比较运算符声明,不会验证这些运算符的实际可调用性。而Boost.MultiIndex的比较运算符是模板化的——它不会直接禁用运算符,只会在尝试比较内部不可比较的元素时才触发编译错误,因此std::three_way_comparable会误判bad_type为可比较类型,进而进入错误分支触发编译失败。

要实现真实可比较性检测,需要自定义概念,直接验证比较表达式的合法性与可调用性,而非仅检查概念满足:

#include <concepts>
#include <type_traits>
#include <iostream>
#include <string>
#include <map>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>

template <typename T>
concept ActuallyComparable = requires(const T& a, const T& b) {
    { a == b } -> std::convertible_to<bool>;
    { a < b } -> std::convertible_to<bool>;
    { a > b } -> std::convertible_to<bool>;
};

template <typename T>
int compare(const T& a, const T& b)
{
    if constexpr (ActuallyComparable<T>) {
        std::cerr << "comparable " << typeid(T).name() << "\n";
        if (a == b) {
            return 0;
        }
        if (a < b) {
            return -1;
        }
        if (a > b) {
            return 1;
        }
    } else {        
        std::cerr << "not comparable " << typeid(T).name() << "\n";
    }
    return 0;
}

// 原结构体定义
struct CompStruct
{
    int         a {};
    std::string b;
    auto        operator<=>(const CompStruct&) const = default;
};

struct UncompStruct
{
    int         a {};
    std::string b;
    auto        operator<=>(const UncompStruct&) const = delete;
};

// Boost.MultiIndex相关定义
namespace bmi = boost::multi_index;
using MultiIndex = bmi::multi_index_container<
    UncompStruct, bmi::indexed_by<bmi::random_access<>>>;
    
struct bad_type : std::map<std::string, MultiIndex>
{};

int main() {
    CompStruct cs_a, cs_b;
    compare(cs_a, cs_b); // 输出"comparable"

    UncompStruct ucs_a, ucs_b;
    compare(ucs_a, ucs_b); // 输出"not comparable"

    bad_type bt_a;
    bad_type bt_b;
    compare(bt_a, bt_b);  // 输出"not comparable",编译通过
}

关键说明

  • ActuallyComparable概念直接检查a == b、a < b、a > b表达式是否合法可调用,且返回值可转换为bool,比std::three_way_comparable更贴近实际可比较需求。
  • 对于Boost.MultiIndex这类模板化比较运算符的类型,std::three_way_comparable会误判其满足概念,但ActuallyComparable会在表达式检查阶段发现内部元素不可比较,从而正确判定类型不可比较。
  • 若仅需检测相等性或部分比较操作,可调整ActuallyComparable中的requires表达式,比如只保留{ a == b } -> std::convertible_to<bool>来检测相等比较能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 12:43:21