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

Clang编译异常是否为编译器Bug?该C++23代码是否合法?

consteval模板代码的跨编译器兼容性疑问

原始代码

#include <memory>

consteval auto func1()
{
    return std::make_unique<int>();
}

template <typename T>
consteval auto func2()
{
    [](auto) -> int {
        func1();
        return {};
    }(0);
}

consteval auto func3()
{
    func2<int>();
}

这段代码可通过GCC编译,但在Clang编译时出现如下错误:

<source>:11:2: error: 即时函数'operator()<int>'在定义前被使用
   11 |         [](auto) -> int {
      |         ^
<source>:11:2: note: 此处请求实例化函数模板特化'func2()::(anonymous class)::operator()<int>'
<source>:19:2: note: 此处请求实例化函数模板特化'func2<int>'
   19 |         func2<int>();
      |         ^
<source>:11:2: note: 'operator()<int>'在此处定义
   11 |         [](auto) -> int {
      |         ^
<source>:12:3: note: 'operator()<int>'是即时函数,因其函数体包含对consteval函数'func1'的调用,且该调用并非常量表达式
   12 |                 func1();
      |                 ^~~~~~~

可编译的修改方案

进行以下任一修改后,代码可通过Clang编译:

  • 将std::make_unique调用移至func2中
  • 移除尾置返回类型(-> int),改为返回int{}
  • 移除auto参数,使lambda的operator()不再是模板
  • 移除template <typename T>,使func2不再是模板
  • 移除func1的consteval修饰
  • 将func1()移至lambda外部,使lambda不再是即时函数
  • 将consteval替换为constexpr
  • 为lambda添加consteval修饰,显式将其设为即时函数(感谢@Fedor)

鉴于该行为的特殊性,这似乎是编译器Bug,但在提交报告前,需确认:这段代码在C++23中是否合法?


MSVC的编译情况

这段代码在MSVC中也编译失败,此时进行以下修改可使其编译:

  • 将std::make_unique调用移至func2中
  • 将func1()移至lambda外部,使lambda不再是即时函数
  • 将consteval替换为constexpr
  • 为lambda添加consteval修饰,显式将其设为即时函数(感谢@Fedor)

附言

该错误出现在我编写的某段模板密集型代码中,我花费数小时才提炼出这个最小复现示例。若有人能找到更简洁的示例,欢迎告知。


无STL的简化版本

class Thing
{
public:
    constexpr Thing() : ptr(new int) {}
    constexpr ~Thing() { delete ptr; }

    // 非必需,仅遵循五法则
    Thing(const Thing&) = delete;
    Thing(Thing&&) = delete;
    Thing& operator=(const Thing&) = delete;
    Thing& operator=(Thing&&) = delete;

private:
    int* ptr;
};

consteval auto func1()
{
    return Thing();
}

template <typename T>
consteval auto func2()
{
    [](auto) -> int {
        func1();
        return {};
    }(0);
}

consteval auto func3()
{
    func2<int>();
}

返回std::string的复现版本

返回std::string时也可复现该错误,此时MSVC可正常编译:

#include <string>

consteval auto func1()
{
    return std::string();
}

template <typename T>
consteval auto func2()
{
    [](auto) -> int {
        func1();
        return {};
    }(0);
}

consteval auto func3()
{
    func2<int>();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 02:49:57