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

consteval上下文无法更新std::variant的编译问题求助

问题

我正在编写C++编译期解析器,使用Microsoft Visual Studio Community 2019(版本17.8.3)时遇到编译问题。以下代码在consteval函数中更新std::variant时触发编译错误,但将函数签名改为constexpr即可正常编译。

问题代码

#include <array>
#include <variant>

using namespace std;

enum class TokenErrors
{
    UNINITIALISED,
    TK_ERROR_SYMBOL,
    TK_ERROR_PATTERN,
    TK_EOF
};

enum class MyTokenType
{
    TK_SYMBOL
};

template <typename TokenType, int num_states>
struct Lexer
{
    std::array<TokenType, num_states> final_states;
};

static consteval auto foo()
{
    auto lxr = Lexer<std::variant<MyTokenType, TokenErrors>, 5>{};
    for (auto &x: lxr.final_states)
        x = TokenErrors::UNINITIALISED;
    return lxr;
}

int main()
{
    auto res = foo();
}

编译错误信息

Build started at 17:22...
1>------ Build started: Project: EfficientCompiler, Configuration: Debug x64 ------
1>Scanning sources for module dependencies...
1>main.cpp
1>C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19): error C2440: '<function-style-cast>': cannot convert from 'initializer list' to 'Lexer<std::variant<MyTokenType,TokenErrors>,5>'
1>C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>Invalid aggregate initialization
1>  C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>  'initializing': cannot convert from 'initializer list' to 'MyTokenType'
1>      C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>      Too many braces around initializer for 'MyTokenType'
1>  C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>  'initializing': cannot convert from 'initializer list' to 'MyTokenType'
1>      C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>      Too many braces around initializer for 'MyTokenType'
1>  C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>  'initializing': cannot convert from 'initializer list' to 'MyTokenType'
1>      C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>      Too many braces around initializer for 'MyTokenType'
1>  C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>  'initializing': cannot convert from 'initializer list' to 'MyTokenType'
1>      C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>      Too many braces around initializer for 'MyTokenType'
1>  C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>  'initializing': cannot convert from 'initializer list' to 'MyTokenType'
1>      C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,19):
1>      Too many braces around initializer for 'MyTokenType'
1>C:\Users\Aakash\source\repos\EfficientCompiler\EfficientCompiler\main.cpp(35,16): error C7595: 'foo': call to immediate function is not a constant expression
1>Done building project "EfficientCompiler.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build completed at 17:22 and took 01.116 seconds ==========
解决方案

这个问题源于VS2019对C++20 consteval特性的实现缺陷,在处理std::variant的默认初始化后赋值时存在兼容性问题。可以通过以下几种方式解决:

  • 显式构造std::variant赋值:修改循环中的赋值语句,显式构造std::variant对象,避免隐式转换的问题:
static consteval auto foo()
{
    auto lxr = Lexer<std::variant<MyTokenType, TokenErrors>, 5>{};
    for (auto &x: lxr.final_states)
        x = std::variant<MyTokenType, TokenErrors>{TokenErrors::UNINITIALISED};
    return lxr;
}
  • 直接初始化数组:在创建Lexer对象时,直接初始化final_states数组,跳过后续赋值步骤,完全在编译期完成初始化:
static consteval auto foo()
{
    return Lexer<std::variant<MyTokenType, TokenErrors>, 5>{
        .final_states = {
            std::variant<MyTokenType, TokenErrors>{TokenErrors::UNINITIALISED},
            std::variant<MyTokenType, TokenErrors>{TokenErrors::UNINITIALISED},
            std::variant<MyTokenType, TokenErrors>{TokenErrors::UNINITIALISED},
            std::variant<MyTokenType, TokenErrors>{TokenErrors::UNINITIALISED},
            std::variant<MyTokenType, TokenErrors>{TokenErrors::UNINITIALISED}
        }
    };
}
  • 升级编译器版本:考虑升级到Visual Studio 2022,新版本对C++20特性的支持更完善,已经修复了这类consteval下的std::variant处理问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:21:02