boost-ext / di

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

How-to bind partial parameters #501

Open heilkn opened 3 years ago

heilkn commented 3 years ago

Hello,

thank you very much for this wonderful library. Aftrer some time now, I have again picked-up re-investigating the library. I have hit some problems in a toy project where I simply do not know how I am supposed to solve it with the tools provided. Therefore, I would like to ask you to give me some hints and consdering to extend or improve the documentation.

Following, is an extracted minimal example of the problem. Assume, we have some types wrapping an external API

struct Device {
    static unsigned constructed;
    Device() { constructed++; }
};
unsigned Device::constructed = 0u;

enum class ShaderType
{
    Vertex,
    Fragment
};

struct ShaderCode
{
    virtual std::vector<char> get() const = 0;
};

struct ShaderBase
{
    ShaderBase(Device const&, ShaderCode const& code, ShaderType type)
    {
        std::cout << (int)type << " : " << code.get().data() << "\n";
    }
};

Then, we create some interface implementation


class ShaderFile : public ShaderCode
{
    std::string _fileName;
public:
    ShaderFile(std::string fileName) : _fileName(std::move(fileName)) {}

    virtual std::vector<char> get() const override {
        return { _fileName.begin(), _fileName.end() };
    }
};

struct StaticShaderCode : ShaderCode
{
    virtual std::vector<char> get() const override {
        decltype(auto) world = "world";
        return { std::begin(world), std::end(world) };
    }
};

and some wrappers to increase type-safety


template <ShaderType shaderType>
struct ShaderModule : ShaderBase
{
    ShaderModule(Device const& device, ShaderCode const& code)
        : ShaderBase(device, code, shaderType) {}
};

Finally, we want to create an application holding some state

struct Application
{
    Device& device;
    //ShaderModule<ShaderType::Vertex>& vertexShader;
    //ShaderModule<ShaderType::Fragment>& fragmentShader;
};

int main(int, char**)
{
    auto injector = di::make_injector(
        // ? what to put here?
        // How to bind ShaderModule<ShaderType::Vertex> using ShaderFile { "hello" }
        // and ShaderModule<ShaderType::Fragment> using StaticShaderCode?
    );
    auto application = injector.create<Application>();

    std::cout << Device::constructed << " devices created";
    assert(Device::constructed == 1u);

    std::cout << std::endl;
}

The code is really just a toy to illustrate the problem I am trying to solve. The class design is most probably not the best, but I think there should be a way to handle this in DI.

I tried using placeholders, but that failed to compile

di::bind<ShaderModule<ShaderType::Vertex>>.to(di::placeholders::_, ShaderFile{ "hello" })

I tried binding lambdas or creating modules, but I don't really know how to do that properly.

I would be really glad hearing how you think this should be done.

Kind regards

Konstantin