修复boost::ext::di工厂扩展传递shared_ptr参数的编译错误
Boost.DI工厂使用智能指针参数编译失败的解决方案
可正常运行的代码
// g++ --version == 13.2.1 // g++ -O0 -g3 -std=gnu++20 -Wall -Wextra -Wpedantic -Werror -Wfatal-errors #include <boost/di/extension/injections/factory.hpp> #include <cassert> #include <memory> class Interface { public: virtual ~Interface() noexcept = default; }; class Implementation : public Interface { public: Implementation(int value) : value_(value) {} int value_ = 0; }; class Example { public: Example(const boost::di::extension::ifactory<Interface, int>& f) { auto impl = f.create(87); assert(dynamic_cast<Implementation*>(impl.get())); } }; namespace di = boost::di; int main() { auto injector = di::make_injector(di::bind<di::extension::ifactory<Interface, int>>().to( di::extension::factory<Implementation>())); auto example = injector.create<std::unique_ptr<Example>>(); assert(example); }
无法编译的代码
#include <boost/di/extension/injections/factory.hpp> #include <cassert> #include <memory> class Interface { public: virtual ~Interface() noexcept = default; }; class Implementation : public Interface { public: Implementation(std::shared_ptr<int> value) : value_(move(value)) {} std::shared_ptr<int> value_; }; class Example { public: Example(const boost::di::extension::ifactory<Interface, std::shared_ptr<int>>& f) { auto ptr = std::make_shared<int>(87); auto impl = f.create(std::shared_ptr<int>(ptr)); // 能否直接传递ptr? assert(dynamic_cast<Implementation*>(impl.get())); } }; namespace di = boost::di; int main() { auto injector = di::make_injector(di::bind<di::extension::ifactory<Interface, std::shared_ptr<int>>>().to( di::extension::factory<Implementation>())); auto example = injector.create<std::unique_ptr<Example>>(); assert(example); }
编译错误输出
In file included from /deps/di/extension/include/boost/di/extension/injections/factory.hpp:11, from /test.cpp:1: /deps/di/include/boost/di.hpp: In instantiation of ‘struct boost::ext::di::v1_3_0::aux::concept_check<boost::ext::di::v1_3_0::concepts::type_<std::shared_ptr<int> >::has_disallowed_qualifiers>’: /deps/di/include/boost/di.hpp:1998:9: required from ‘std::unique_ptr<I> boost::ext::di::v1_3_0::extension::factory_impl<TInjector, T, boost::ext::di::v1_3_0::extension::ifactory<I, TArgs ...> >::create(TArgs&& ...) const [with TInjector = boost::ext::di::v1_3_0::core::injector<boost::ext::di::v1_3_0::config, boost::ext::di::v1_3_0::core::pool<boost::ext::di::v1_3_0::aux::type_list<> >, boost::ext::di::v1_3_0::core::dependency<boost::ext::di::v1_3_0::scopes::instance, boost::ext::di::v1_3_0::extension::ifactory<Interface, std::shared_ptr<int> >, boost::ext::di::v1_3_0::extension::factory<Implementation>, boost::ext::di::v1_3_0::no_name, void, boost::ext::di::v1_3_0::core::none> >; T = Implementation; I = Interface; TArgs = {std::shared_ptr<int>}]’ /deps/di/extension/include/boost/di/extension/injections/factory.hpp:30:22: required from here /deps/di/include/boost/di.hpp:379:20: error: static assertion failed: constraint not satisfied 379 | static_assert(T::value, "constraint not satisfied"); | ^~~~~ /deps/di/include/boost/di.hpp:379:20: note: ‘boost::ext::di::v1_3_0::aux::integral_constant<bool, false>::value’ evaluates to false /deps/di/include/boost/di.hpp: In instantiation of ‘std::unique_ptr<I> boost::ext::di::v1_3_0::extension::factory_impl<TInjector, T, boost::ext::di::v1_3_0::extension::ifactory<I, TArgs ...> >::create(TArgs&& ...) const [with TInjector = boost::ext::di::v1_3_0::core::injector<boost::ext::di::v1_3_0::config, boost::ext::di::v1_3_0::core::pool<boost::ext::di::v1_3_0::aux::type_list<> >, boost::ext::di::v1_3_0::core::dependency<boost::ext::di::v1_3_0::scopes::instance, boost::ext::di::v1_3_0::extension::ifactory<Interface, std::shared_ptr<int> >, boost::ext::di::v1_3_0::extension::factory<Implementation>, boost::ext::di::v1_3_0::no_name, void, boost::ext::di::v1_3_0::core::none> >; T = Implementation; I = Interface; TArgs = {std::shared_ptr<int>}]’ /deps/di/extension/include/boost/di/extension/injections/factory.hpp:30:22: required from here /deps/di/include/boost/di.hpp:1998:9: error: no type named ‘type’ in ‘struct boost::ext::di::v1_3_0::aux::concept_check<boost::ext::di::v1_3_0::concepts::type_<std::shared_ptr<int> >::has_disallowed_qualifiers>’ 1998 | bind | ^~~~
解决方案
1. 编译失败原因
Boost.DI的extension::factory默认会自动解析目标类的构造函数参数,当参数是智能指针这类非原始类型时,注入器会认为该参数应由自身提供而非外部传递,从而触发概念检查失败。我们需要显式告知工厂:构造函数中的std::shared_ptr<int>参数是由create方法外部传入的,而非注入器注入。
2. 修改后的可编译代码
#include <boost/di/extension/injections/factory.hpp> #include <cassert> #include <memory> class Interface { public: virtual ~Interface() noexcept = default; }; class Implementation : public Interface { public: Implementation(std::shared_ptr<int> value) : value_(std::move(value)) {} std::shared_ptr<int> value_; }; class Example { public: Example(const boost::di::extension::ifactory<Interface, std::shared_ptr<int>>& f) { auto ptr = std::make_shared<int>(87); auto impl = f.create(ptr); // 直接传递ptr即可 assert(dynamic_cast<Implementation*>(impl.get())); assert(*impl->value_ == 87); // 验证参数传递正确 } }; namespace di = boost::di; int main() { auto injector = di::make_injector(di::bind<di::extension::ifactory<Interface, std::shared_ptr<int>>>().to( di::extension::factory<Implementation, std::shared_ptr<int>>())); // 显式指定外部传递的参数类型 auto example = injector.create<std::unique_ptr<Example>>(); assert(example); }
3. 修改点说明
- 绑定工厂时显式指定参数类型:将
di::extension::factory<Implementation>()改为di::extension::factory<Implementation, std::shared_ptr<int>>(),明确告诉Boost.DI该工厂需要外部传入std::shared_ptr<int>类型的参数。 - 直接传递
ptr到create方法:create方法支持完美转发,传递左值ptr会触发拷贝构造,传递std::move(ptr)会触发移动构造,无需显式构造新的std::shared_ptr<int>。
关于f.create传递参数的疑问
可以直接传递ptr,无需显式构造新的std::shared_ptr<int>。create方法的参数是可变参数模板TArgs&&...,支持完美转发:
- 传递
ptr(左值):会调用std::shared_ptr的拷贝构造函数,增加引用计数。 - 传递
std::move(ptr)(右值):会调用std::shared_ptr的移动构造函数,不会增加引用计数,效率更高。
内容的提问来源于stack exchange,提问作者SVA522
相关产品推荐
相关产品推荐

