This code is working fine :
// 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);
}
But this one does not compile :
#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)); // can i just pass `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);
}
Output is :
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
| ^~~~
How to fix this code ? Thanks for your replies.
Regards,
XS
Best I understand from playing around with many (many) setups, including ditching the factory at all, is that you're simply not supposed to (smart) bind pointers to primitives, which is what the factory ends up doing too. You're supposed to bind pointers to interfaces.
You can probably trick the system by wrapping your pointer in a value type, like this:
#include "https://raw.githubusercontent.com/boost-ext/di/cpp14/include/boost/di.hpp"
#include <cassert>
#include <iostream>
#include <memory>
namespace di = boost::di;
template <typename T> struct Wrapped {
std::shared_ptr<T> value;
explicit Wrapped(T v = {}) : value(std::make_shared<T>(std::move(v))) {}
// for debug output
friend std::ostream& operator<<(std::ostream& os, Wrapped const& a) {
return a.value ? os << *a.value : os << "#";
}
};
// using Arg = int;
using Arg = Wrapped<int>;
struct Interface {
virtual ~Interface() noexcept = default;
};
struct Implementation : Interface {
Implementation(Arg value) : value_(std::move(value)) {
std::cout << __PRETTY_FUNCTION__ << "(" << value_ << ")" << std::endl;
}
Arg value_{};
};
struct Example {
Example(std::unique_ptr<Interface> impl) {
assert(dynamic_cast<Implementation*>(impl.get()));
}
};
int main() {
static_assert(di::concepts::boundable<Arg>::value);
auto injector = make_injector( //
di::bind<int>().to(42), //
di::bind<Interface>() //
.to<Implementation>() //
);
auto example = injector.create<std::unique_ptr<Example>>();
assert(example);
}
Printing
Implementation::Implementation(Arg)(42)
In case you really want the injectee to instantiate dynamic number of instances without directly sharing the entire injector by reference:
#include <boost/di.hpp>
#include <boost/di/extension/injections/factory.hpp>
#include <cassert>
#include <iostream>
#include <memory>
namespace di = boost::di;
template <typename T> struct Wrapped {
std::shared_ptr<T> value;
/*explicit*/ Wrapped(T v = {}) : value(std::make_shared<T>(std::move(v))) {}
// for debug output
friend std::ostream& operator<<(std::ostream& os, Wrapped const& a) {
return a.value ? os << *a.value : os << "#";
}
};
// using Arg = int;
using Arg = Wrapped<int>;
struct Interface {
virtual ~Interface() noexcept = default;
};
using TFactory = di::extension::ifactory<Interface>;
struct Implementation : Interface {
Implementation(Arg value) : value_(std::move(value)) {
std::cout << __PRETTY_FUNCTION__ << "(" << value_ << ")" << std::endl;
}
Arg value_{};
};
struct Example {
Example(TFactory const& f) {
std::generate_n(back_inserter(impls), 10, [&f]{ return f.create(); });
}
std::vector<std::unique_ptr<Interface>> impls;
};
int main() {
static_assert(di::concepts::boundable<Arg>::value);
auto injector = make_injector( //
di::bind<int>().to(43), //
di::bind<TFactory>() //
.to(di::extension::factory<Implementation>()) //
);
auto example = injector.create<std::unique_ptr<Example>>();
assert(example);
}
Printing
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Implementation::Implementation(Arg)(43)
Arg
Of course this again works with the constructor argument as long as the Arg
satisfies the boundable
constraint again:
using TFactory = di::extension::ifactory<Interface, Arg>;
struct Example {
Example(TFactory const& f) {
generate_n( //
back_inserter(impls), 10, //
[i = 0, &f]() mutable { return f.create(42 * i++); });
}
std::vector<std::unique_ptr<Interface>> impls;
};
int main() {
static_assert(di::concepts::boundable<Arg>::value);
auto injector = make_injector( //
di::bind<TFactory>() //
.to(di::extension::factory<Implementation>()) //
);
auto example = injector.create<std::unique_ptr<Example>>();
assert(example);
}
Printing
Implementation::Implementation(Arg)(0)
Implementation::Implementation(Arg)(42)
Implementation::Implementation(Arg)(84)
Implementation::Implementation(Arg)(126)
Implementation::Implementation(Arg)(168)
Implementation::Implementation(Arg)(210)
Implementation::Implementation(Arg)(252)
Implementation::Implementation(Arg)(294)
Implementation::Implementation(Arg)(336)
Implementation::Implementation(Arg)(378)