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

使用类型擦除包装器解决概念自引用问题

类型擦除包装器构造函数的约束自引用问题及解决方案

问题描述

我实现了一个C++类型擦除包装器,其构造函数通过约束确保仅接受可构造std::decay_t<T>的参数:

#include <concepts>
#include <type_traits>
#include <utility>

struct type_erasing_wrapper {
    template<typename T>
        requires(
                not std::same_as<std::remove_cvref_t<T>, type_erasing_wrapper>
            and std::constructible_from<std::decay_t<T>, T>
        )
    type_erasing_wrapper(T&& s) :
        ptr{new std::decay_t<T>(std::forward<T>(s))},
        destroy{
            [](void* ptr) noexcept {
                delete static_cast<std::decay_t<T>*>(ptr);
            }
        } {}

    // 移动构造函数、赋值运算符及析构函数...

    void* ptr;
    void(*destroy)(void*) noexcept;
};

原本约束工作正常,但当引入如下holder结构体并添加静态断言后,Clang/GCC提示构造函数约束存在自引用问题:

template<typename T>
struct holder {
    explicit holder(T object) : object{std::move(object)} {}

    T object;
};

static_assert(std::constructible_from<type_erasing_wrapper, holder<type_erasing_wrapper>>);

我尝试修改holder为模板构造版本,但兼容性因编译器版本而异;改为聚合类可兼容所有编译器,但我不想限制holder的实现方式。

问题求解

  1. 除修改holder外,是否有不修改API且符合标准的解决方案?
  2. MSVC可编译所有示例,这是否是Clang/GCC的bug?

解决方案(不修改holder)

问题根源在于:当T = holder<type_erasing_wrapper>时,检查std::constructible_from<std::decay_t<T>, T>会触发holder<type_erasing_wrapper>的构造合法性验证,而holder的构造需要初始化type_erasing_wrapper成员,这又会递归检查type_erasing_wrapper的构造约束,形成无限循环。

要解决这个问题,只需将约束中的concept式检查替换为类型 trait式检查,避免触发递归的concept验证:

template<typename T>
    requires(
            not std::same_as<std::remove_cvref_t<T>, type_erasing_wrapper>
        and std::is_constructible_v<std::decay_t<T>, T>
    )
type_erasing_wrapper(T&& s) :
    ptr{new std::decay_t<T>(std::forward<T>(s))},
    destroy{
        [](void* ptr) noexcept {
            delete static_cast<std::decay_t<T>*>(ptr);
        }
    } {}

std::is_constructible_v是编译期常量表达式,求值过程不会触发concept的递归约束检查,因此能打破循环。

关于编译器行为的说明

MSVC可编译并非Clang/GCC的bug,而是不同编译器对约束递归的处理策略差异:

  • Clang/GCC严格遵循C++标准中关于约束求值的规则,当检测到无限递归的约束检查时,直接报错终止编译。
  • MSVC采用了更宽松的递归处理逻辑,可能在递归到一定深度后终止检查并判定约束满足,但这种行为并不符合标准要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.01 15:17:30