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

C++17 std::visit相关可变参数模板代码语法通俗解释咨询

C++17 std::visit配套访问器代码解释

你贴的这段是C++17中配合std::visit使用的经典重载访问器实现,逐段拆解语法和逻辑如下:

完整示例代码

#include <iostream>
#include <string>
#include <variant>

template<typename... Targs>
struct VariantType : Targs... {
    using Targs::operator()...;
};

template<typename... Targs>
VariantType(Targs...) -> VariantType<Targs...>;

int main() {
    std::variant<int, double, std::string> var;
    var = "Hello, world!";
    std::visit(
        VariantType {
            [] (int i) { std::cout << "int: " << i << std::endl; },
            [] (double d) { std::cout << "double: " << d << std::endl; },
            [] (const std::string& str) { std::cout << "std::string: " << str << std::endl; }
        }, var
    );
}

逐段语法规则说明

1. 可变参数结构体定义

template<typename... Targs>
struct VariantType : Targs... {
    using Targs::operator()...;
};

这部分用到三个核心C++语法规则:

  • template<typename... Targs>:声明可变参数模板,支持传入任意数量的类型作为模板参数
  • struct VariantType : Targs...:可变参数继承,让VariantType同时继承所有传入的Targs类型。示例中传入的三个参数都是lambda,每个lambda本质是编译器生成的独立匿名类,自带一个operator()调用运算符
  • using Targs::operator()...;:C++17折叠表达式形式的using声明,作用是把所有父类(即传入的lambda类)的operator()全部引入当前类的作用域,避免继承来的同名operator()因为同名隐藏规则导致重载决议失败,让编译器能找到所有入参版本的调用运算符。

2. 类模板推导指引

template<typename... Targs>
VariantType(Targs...) -> VariantType<Targs...>;

这是C++17新增的自定义类模板实参推导(CTAD)规则:当你用花括号传参构造VariantType时,编译器会自动根据传入参数的类型,推导出VariantType的模板参数类型,不需要手动显式指定模板参数——毕竟lambda的类型是编译器生成的匿名类型,开发者根本无法手动写出。

实现运行逻辑

main函数中的调用流程非常直接:

  • 定义可存储int/double/std::string三种类型的std::variant变量,赋值后实际存储的是std::string类型的值
  • 构造VariantType实例时传入三个分别对应三种variant存储类型的lambda,编译器自动生成继承了三个lambda的访问器对象,这个对象自带三个重载的operator(),分别匹配三种入参
  • std::visit会自动识别variant当前存储的实际类型,调用访问器中对应入参的operator()重载,最终输出std::string: Hello, world!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:39:16