C++模板输入中使用std::variant报错,求问题分析与解决
问题分析与解决:std::variant使用错误导致类型转换失败
报错信息
main.cpp:22:7: note: no known conversion for argument 1 from ‘MyClass<InputClass1>’ to ‘const MyClass<VariantType>&’ main.cpp:22:7: note: candidate: ‘constexpr MyClass<VariantType>::MyClass(MyClass<VariantType>&&)’ main.cpp:22:7: note: no known conversion for argument 1 from ‘MyClass<InputClass1>’ to ‘MyClass<VariantType>&&’
原始代码
#include <iostream> #include <variant> #include <memory> using namespace std; struct InputClass1{ static std::string MyName(){ return "InputClass1"; } }; struct InputClass2{ static std::string MyName(){ return "InputClass2"; } }; template<class InputClass> class MyClass{ public: MyClass(){ std::cout<<InputClass::MyName(); } }; class MyCreatorClass{ using VariantType = std::variant<InputClass1, InputClass2>; public: static std::shared_ptr<MyClass<VariantType>> create(){ return std::make_shared<MyClass<VariantType>>(MyClass<InputClass1>()); } // Am I using the variant the right way here? }; int main() { cout<<"Hello World"; MyCreatorClass::create(); return 0; }
用户疑问
我是否正确使用了std::variant?请帮忙分析并解决该报错问题。
问题分析
你对std::variant的使用完全偏离了正确方向:
MyClass<VariantType>和MyClass<InputClass1>是完全独立的模板实例化类型,二者之间没有任何继承或隐式转换关系,编译器无法将MyClass<InputClass1>对象转换成MyClass<VariantType>的构造参数。std::variant的核心作用是在单个对象中存储多种类型中的某一种,不是用来作为模板参数去兼容其他模板实例的,你的写法完全违背了它的设计逻辑。
解决方案
根据常见的需求场景,提供两种修正方案:
方案1:让MyClass支持处理std::variant类型
修改MyClass,新增支持std::variant的构造函数,使其能接收包含InputClass1或InputClass2的variant对象:
#include <iostream> #include <variant> #include <memory> #include <type_traits> using namespace std; struct InputClass1{ static std::string MyName(){ return "InputClass1"; } }; struct InputClass2{ static std::string MyName(){ return "InputClass2"; } }; template<class InputClass> class MyClass{ public: // 原构造函数,处理普通输入类型 MyClass(){ std::cout << InputClass::MyName() << endl; } // 新增构造函数,处理variant类型 template<typename... Ts> MyClass(const std::variant<Ts...>& var){ std::visit([](const auto& obj){ std::cout << std::decay_t<decltype(obj)>::MyName() << endl; }, var); } }; class MyCreatorClass{ using VariantType = std::variant<InputClass1, InputClass2>; public: static std::shared_ptr<MyClass<VariantType>> create(){ // 先创建包含InputClass1的variant实例,再传给MyClass构造 return std::make_shared<MyClass<VariantType>>(VariantType{InputClass1{}}); } }; int main() { cout << "Hello World" << endl; MyCreatorClass::create(); return 0; }
方案2:用variant持有不同类型的MyClass实例
如果需求是让create()返回一个能容纳MyClass<InputClass1>或MyClass<InputClass2>的容器,应该让variant存储这两种MyClass的智能指针:
#include <iostream> #include <variant> #include <memory> using namespace std; struct InputClass1{ static std::string MyName(){ return "InputClass1"; } }; struct InputClass2{ static std::string MyName(){ return "InputClass2"; } }; template<class InputClass> class MyClass{ public: MyClass(){ std::cout << InputClass::MyName() << endl; } }; class MyCreatorClass{ // variant存储不同MyClass的shared_ptr using VariantType = std::variant<std::shared_ptr<MyClass<InputClass1>>, std::shared_ptr<MyClass<InputClass2>>>; public: static VariantType create(){ // 返回持有MyClass<InputClass1>实例的variant return std::make_shared<MyClass<InputClass1>>(); } }; int main() { cout << "Hello World" << endl; auto var = MyCreatorClass::create(); // 可以用std::visit访问variant中的对象 std::visit([](const auto& ptr){}, var); return 0; }
内容的提问来源于stack exchange,提问作者user1008636
相关产品推荐
相关产品推荐

