boost-ext / di

C++14 Dependency Injection Library
https://boost-ext.github.io/di
1.13k stars 136 forks source link

Factory extension creating object instead of using value supplied in .create() #531

Open dfontenot opened 2 years ago

dfontenot commented 2 years ago

I'm running into an issue using the factory extension. It seems that the ref that is passed to the .create() method for the injected factory is ignored, and DI is instead instantiating a new one. It looks like DI is trying to create a NonInjected for me, but in this example I wanted to have NonInjectedrepresent something that lives outside of the bindings. I used the existing guides on the website as a guide for the code.

Below is a little messy, and probably unnecessarily nested, because it's a rough translation of some existing code that removes its domain-specific stuff.

Please let me know if this is just a misunderstanding of how the library works.

Expected Behavior

Program output:

in usesfactoried
in NonInjected ctor 4.5
before <NonInjected d=4.5>
in factoried ctor <NonInjected d=4.5>
in factoried 42 <NonInjected d=4.5>

Actual Behavior

Program output:

in usesfactoried
in NonInjected ctor 4.5
before <NonInjected d=4.5>
in NonInjected ctor 0
in factoried ctor <NonInjected d=0>
in factoried 42 <NonInjected d=0>

Steps to Reproduce the Problem

#include <iostream>
#include <boost/di.hpp>
#include <boost/di/extension/injections/factory.hpp>
#include <memory>
#include <cassert>

namespace di = boost::di;
namespace ext = di::extension;

using std::make_unique;
using std::cout;
using std::endl;
using std::ostream;

// some class that isn't injected
class NonInjected {
    public:
    double d;

    explicit NonInjected(double d) : d(d) {
        cout << "in NonInjected ctor " << d << endl;
    }

    friend auto operator<<(ostream& os, NonInjected const& m) -> ostream& {
        return os << "<NonInjected d=" << m.d << ">";
    }
};

// some regular class that is injected
struct IRegular {
    virtual ~IRegular() noexcept = default;
};

class Regular : public IRegular {
public:
    explicit Regular(int i) : i(i) {}
    int i;
};

// is used as a factory
struct IFactoried {
    virtual ~IFactoried() noexcept = default;
    virtual void run() = 0;
};

class Factoried : public IFactoried {
    Regular reg_;
    NonInjected& notInjected_;

public:
    Factoried(Regular& reg, NonInjected& notInjected) :
        reg_(reg),
        notInjected_(notInjected) {

        cout << "in factoried ctor " << notInjected << endl;
    }

    void run() override {
        cout << "in factoried " << reg_.i << " " << notInjected_ << endl;
    }
};

using InjectableFactory = ext::ifactory<IFactoried, NonInjected& >;
using RealFactory = ext::factory<Factoried>;

// uses factoried as a factory

struct IUsesFactoried {
    virtual ~IUsesFactoried() noexcept = default;
    virtual void run() = 0;
};

class UsesFactoried : public IUsesFactoried {
    InjectableFactory& fac_;

public:
    UsesFactoried(InjectableFactory& fac) :
        fac_(fac) {}

    void run() override {
        cout << "in usesfactoried" << endl;

        auto managed = make_unique<NonInjected>(4.5);
        cout << "before " << *managed << endl;

        auto boxed = fac_.create(*managed);
        auto f = boxed.get();
        f->run();
    }
};

int main() {
    const auto injector = di::make_injector(
        di::bind<InjectableFactory>().to(RealFactory {}),
        di::bind<IRegular>().to<Regular>(),
        di::bind<IFactoried>().to<Factoried>(),
        di::bind<IUsesFactoried>().to<UsesFactoried>(),
        di::bind<int>().to(42)
    );

    auto output = injector.create<UsesFactoried>();
    output.run();
}

Specifications