Boost.DI: dependency injection in C ++

Original author: Krzysztof Jusiak
  • Transfer
  • Tutorial
“Do not call us. We will call you ourselves. ” - Hollywood principle

Dependency Injection (DI) means transferring (introducing) one or more dependencies to any object (client, component) in such a way that after implementation this dependence becomes part of the state of the object. This is a bit like the design pattern Strategy, with the only difference being that the strategy is set only once - in the constructor. DI allows you to create a more loosely coupled application architecture that lends itself better to support and testing.

So, pluses again:
  • Decreases component connectivity (separates business logic from object creation)
  • Allows you to write more supported code (we can easily implement different dependencies in the same objects)
  • Allows you to write more testable code (we can use stubs and moki more easily)


No dependency injectionWith dependency injection
class example {                         
public:  
    example()                           
        : logic_(new logic{})           
        , logger_(                      
            logger_factory::create()    
          )                             
    { }  
    int run() const;                    
private: 
    shared_ptr logic_;          
    shared_ptr logger_;        
};                             

 class example {
 public:
     example(shared_ptr logic
           , shared_ptr logger)
       : logic_(logic), logger_(logger)
     { }
     int run() const;
 private:
     shared_ptr logic_;
     shared_ptr logger_;
 };



Boost.DI is a library for implementing dependency injection in C ++. To use it, you just need to include one header file in your code. The purpose of the library is to simplify the creation of objects using automatic dependency injection:
  • Reducing the number of bottlenecks in the code - no extra factories, no creation of objects in only a certain order
  • Simplified code support - changing the designer signature will not affect DI configuration
  • Simplified Testing - Automatic Mock Injection
  • Better control over what and when to create
  • Better understanding of the code in terms of the hierarchy of objects


Manual Dependency InjectionBoost.DI
int main() {                            
    /*boilerplate code*/                
    auto logic = make_shared();  
    auto logger = make_shared();
    return example{logic, logger}.run();
}        

int main() {
    auto injector = di::make_injector(
        di::bind
      , di::bind
    );
    return injector.create().run();
}


Once again - why use dependency injection




image



Where to begin?



  • Take a compiler with C ++ 14 support (Clang-3.4 +, GCC-5.0 +). Boost library not required
  • Read this document
  • Read the tutorial
  • Read the documentation


In general, everything you need to work with the library, this di.hpp file

    // main.cpp
    #include "di.hpp"
    int main() { }


    $CXX -std=c++1y -I. main.cpp


Let's assume that all the examples below include boost / di.hpp and define the di namespace as alias boost :: di.

#include 
namespace di = boost::di;
//
struct i1 { virtual ~i1() = default; virtual void dummy1() = 0; };
struct i2 { virtual ~i2() = default; virtual void dummy2() = 0; };
struct impl1 : i1 { void dummy1() override { } };
struct impl2 : i2 { void dummy2() override { } };
struct impl : i1, i2 { void dummy1() override { } void dummy2() override { } };


Injector


Create an empty injectorTest
auto injector = di::make_injector();    

assert(0 == injector.create());         


Bindings


Examples
More examples
Binding an interface to an implementationTest
auto injector = di::make_injector(di::bind);

auto object = injector.create>();             
assert(dynamic_cast(object.get()));


Binding multiple interfaces to one implementationTest
auto injector = di::make_injector(di::bind, impl>);     

auto object1 = injector.create>();            
auto object2 = injector.create>();
assert(dynamic_cast(object1.get()));
assert(dynamic_cast(object2.get()));


Binding a type to a value computed at compile timeTest
template using int_ = integral_constant;    
auto injector = di::make_injector(di::bind>);

assert(42 == injector.create());                        


Binding a Type to a ValueTest
auto injector = di::make_injector(di::bind.to(42));

assert(42 == injector.create());                     


Implementation


Examples
More examples
Deploy through a regular constructorTest
struct c {                             
    c(int a, double d) : a(a), d(d) { }
    int a = 0;                         
    double d = 0.0;                    
};      
auto injector = di::make_injector(     
    di::bind.to(42)               
  , di::bind.to(87.0)          
);

auto object = injector.create();
assert(42 == object.a);
assert(87.0 == object.d);


Implementation through AggregationTest
struct c {                        
    int a = 0;                    
    double d = 0.0;               
}; 
auto injector = di::make_injector(
    di::bind.to(42)          
  , di::bind.to(87.0)     
);          

auto object = injector.create();
assert(42 == object.a);
assert(87.0 == object.d);


Implementation through the constructor if there are
several constructors (the one with the
largest number of parameters will be selected )
Test
struct c {                             
    c();                               
    c(int a) : a(a) { }                
    c(int a, double d) : a(a), d(d) { }
    int a = 0;                         
    double d = 0.0;                    
};      
auto injector = di::make_injector(     
    di::bind.to(42)               
  , di::bind.to(87.0)          
);

auto object = injector.create();             
assert(42 == object.a);
assert(87.0 == object.d);


Deployment through the constructor when there are
choices (using BOOST_DI_INJECT)
Test
struct c {                             
    c(double d, int a) : a(a), d(d) { }
    BOOST_DI_INJECT(c, int a, double d)
        : a(a), d(d) { }               
    int a = 0;                         
    double d = 0.0;                    
};      
auto injector = di::make_injector(     
    di::bind.to(42)               
  , di::bind.to(87.0)          
);

auto object = injector.create();        
assert(42 == object.a);
assert(87.0 == object.d);


Deployment through the constructor when there are
choices (using BOOST_DI_INJECT_TRAITS)
Test
struct c {                              
    BOOST_DI_INJECT_TRAITS(int, double);
    c(double d, int a) : a(a), d(d) { } 
    c(int a, double d) : a(a), d(d) { } 
    int a = 0;                          
    double d = 0.0;                     
};       
auto injector = di::make_injector(      
    di::bind.to(42)                
  , di::bind.to(87.0)           
);

auto object = injector.create();        
assert(42 == object.a);
assert(87.0 == object.d);


Deployment through the constructor when there are
choices (using di :: ctor_traits)
Test
struct c {                              
    c(double d, int a) : a(a), d(d) { } 
    c(int a, double d) : a(a), d(d) { } 
    int a = 0;                          
    double d = 0.0;                     
};       
namespace boost { namespace di {        
template<>                              
struct ctor_traits {                 
    BOOST_DI_INJECT_TRAITS(int, double);
};       
}} // boost::di                         
auto injector = di::make_injector(      
    di::bind.to(42)                
  , di::bind.to(87.0)           
);       

auto object = injector.create();       
assert(42 == object.a);
assert(87.0 == object.d);


Annotations


Examples
Deploy through annotated constructorsTest
auto int1 = []{};                   
auto int2 = []{};                   
struct c {                          
    BOOST_DI_INJECT(c               
        , (named = int1) int a      
        , (named = int2) int b)     
        : a(a), b(b)                
    { }                             
    int a = 0;                      
    int b = 0;                      
};   
auto injector = di::make_injector(  
    di::bind.named(int1).to(42)
  , di::bind.named(int2).to(87)
);   

auto object = injector.create();
assert(42 == object.a);
assert(87 == object.b);


Deploy through annotated constructors
using named parameters
Test
auto n1 = []{};                         
auto n2 = []{};                         
struct c {                              
  BOOST_DI_INJECT(c                     
      , (named = n1) int a              
      , (named = n1) int b              
      , (named = n2) int c              
      , int d                           
      , (named = n1) string s)          
  : i1(i1), i2(i2), i3(i3), i4(i4), s(s)
  { }    
  int i1 = 0;                           
  int i2 = 0;                           
  int i3 = 0;                           
  int i4 = 0;                           
  string s;                             
};       
auto injector = di::make_injector(      
    di::bind.named(n1).to(42)      
  , di::bind.named(n2).to(87)      
  , di::bind.named(n1).to("str")
);       

auto object = injector.create();          
assert(42 == object.i1);
assert(42 == object.i2);
assert(87 == object.i3);
assert(0 == object.i4);
assert("str" == c.s);


Implementation through annotated constructors with
the implementation of the constructor implementation
Test
auto int1 = []{};                   
auto int2 = []{};                   
struct c {                          
    BOOST_DI_INJECT(c               
        , (named = int1) int a      
        , (named = int2) int b);    
    int a = 0;                      
    int b = 0;                      
};   
c::c(int a, int b) : a(a), b(b) { } 
auto injector = di::make_injector(  
    di::bind.named(int1).to(42)
  , di::bind.named(int2).to(87)
);           

auto object = injector.create();       
assert(42 == object.a);
assert(87 == object.b);


Внедрение через аннотированные конструкторы с
использованием di::ctor_traits
Тест
auto int1 = []{};                   
auto int2 = []{};                   
struct c {                          
    c(int a, int b) : a(a), b(b) { }
    int a = 0;                      
    int b = 0;                      
};   
namespace boost { namespace di {    
template<>                          
struct ctor_traits {             
    BOOST_DI_INJECT_TRAITS(         
        (named = int1) int          
      , (named = int2) int);        
};   
}} // boost::di                     
auto injector = di::make_injector(  
    di::bind.named(int1).to(42)
  , di::bind.named(int2).to(87)
);                

auto object = injector.create();         
assert(42 == object.a);
assert(87 == object.b);


Области видимости


Примеры
Ещё примеры

Вывод области видимости (по-умолчанию)Тест
struct c {                          
    shared_ptr sp; /*singleton*/
    unique_ptr up; /*unique*/   
    int& i; /*external*/            
    double d; /*unique*/            
};   
auto i = 42;                        
auto injector = di::make_injector(  
    di::bind             
  , di::bind             
  , di::bind.to(ref(i))        
  , di::bind.to(87.0)       
);                      

auto object1 = injector.create>();
auto object2 = injector.create>();
assert(object1->sp == object2->sp);
assert(object1->up != object2->up);
assert(42 == object1->i);
assert(&i == &object1->i;
assert(42 == object2->i);
assert(&i == &object2->i);
assert(87.0 == object1->d);
assert(87.0 == object2->d);


ТипВыведенная область видимости
Tunique
T&ошибка — должен быть связан как external
const T&unique (временный)
T*unique (передача владения)
const T*unique (передача владения)
T&&unique
unique_ptrunique
shared_ptrsingleton
weak_ptrsingleton

Уникальная область видимостиТест
auto injector = di::make_injector(    
    di::bind.in(di::unique)
);     

assert(injector.create>()
       !=
       injector.create>()
     | );


Разделяемая область видимости (в пределах потока)Тест
auto injector = di::make_injector(    
    di::bind.in(di::shared)
);     

assert(injector.create>()
       ==
       injector.create>()
     | );


Синглтон (разделяем между потоками)Тест
auto injector = di::make_injector(      
   di::bind.in(di::singleton)
);       

assert(injector.create>()
       ==
       injector.create>());


Область видимости сессииТест
auto my_session = []{};           
auto injector = di::make_injector(
    di::bind.in(       
        di::session(my_session)   
    )                             
); 

assert(nullptr == injector.create>());
injector.call(di::session_entry(my_session));
assert(injector.create>()
       ==
       injector.create>());
injector.call(di::session_exit(my_session));
assert(nullptr == injector.create>());


Внешняя область видимостиТест
auto l = 42l;                          
auto b = false;                        
auto injector = di::make_injector(     
   di::bind>             
 , di::bind.to(42)                
 , di::bind.to(make_shared())
 , di::bind.to(ref(l))           
 , di::bind.to([]{return 87;})  
 , di::bind.to(                    
     [&](const auto& injector)         
        -> shared_ptr {            
            if (b) {                   
              return injector.template 
                create<                
                  shared_ptr>();
            }                          
            return nullptr;            
     }  
   )    
);      

assert(42 == injector.create()); // external has priority
assert(injector.create>()
       ==
       injector.create>()
);
assert(l == injector.create());
assert(&l == &injector.create());
assert(87 == injector.create());
{
auto object = injector.create>();
assert(nullptr == object);
}
{
b = true;
auto object = injector.create>();
assert(dynamic_cast(object.get()));
} 


Специальная область видимостиТест
struct custom_scope {                   
  static constexpr                      
      auto priority = false;            
  template      
  struct scope {                        
    template  
    auto create(const TProvider& pr) {  
      return                            
        shared_ptr{pr.get()};
    }    
  };     
};       
auto injector = di::make_injector(      
  di::bind.in(custom_scope{})
);       

assert(injector.create>()
       !=
       injector.create>()
);




Модули


Примеры
МодульТест
struct c {                           
    c(unique_ptr i1              
    , unique_ptr i2              
    , int i) : i1(move(i1))          
             , i2(move(i2)), i(i)    
    { }                              
    unique_ptr i1;               
    unique_ptr i2;               
    int i = 0;                       
};    
struct module1 {                     
    auto configure() const noexcept {
        return di::make_injector(    
            di::bind      
          , di::bind.to(42)     
        );                           
    } 
};    
struct module2 {                     
    auto configure() const noexcept {
        return di::make_injector(    
            di::bind      
        );                           
    };                               
};    
auto injector = di::make_injector(   
    module1{}, module2{}             
);    

auto object = injector.create>();
assert(dynamic_cast(object->i1.get()));
assert(dynamic_cast(object->i2.get()));
assert(42 == object->i);
auto up1 = injector.create>();
assert(dynamic_cast(up1.get()));
auto up2 = injector.create>();
assert(dynamic_cast(up2.get()));


Модуль, открывающий типТест
struct c {                          
    c(shared_ptr i1             
    , shared_ptr i2             
    , int i) : i1(i1), i2(i2), i(i) 
    { }                             
    shared_ptr i1;              
    shared_ptr i2;              
    int i = 0;                      
};   
struct module {                     
    di::injector configure()     
    const noexcept;                 
    int i = 0;                      
};   
di::injector // открывает c         
module::configure() const noexcept {
    return di::make_injector(       
        di::bind         
      , di::bind         
      , di::bind.to(i)         
    );                              
}    
auto injector = di::make_injector(  
    module{42}                      
);

auto object = injector.create();
assert(dynamic_cast(object.i1.get()));
assert(dynamic_cast(object.i2.get()));
assert(42 == object.i);
// injector.create>() // ошибка компиляции
// injector.create>() // ошибка компиляции


Модуль, открывающий несколько типовТест
struct module {                      
    di::injector configure() 
    const noexcept;                  
    int i = 0;                       
};    
di::injector // открывает i1, i2
module::configure() const noexcept { 
    return di::make_injector(        
        di::bind          
      , di::bind          
    );                               
}     
auto injector = di::make_injector(   
    module{}                         
);                    

auto up1 = injector.create>();
assert(dynamic_cast(up1.get()));
auto up2 = injector.create>();
assert(dynamic_cast(up2.get()));


Модуль открытого типа с аннотациейТест
auto my = []{};                        
struct c {                             
    BOOST_DI_INJECT(c                  
      , (named = my) unique_ptr up)
      : up(up)                         
    { } 
    unique_ptr up;                 
};      
di::injector module =              
    di::make_injector(                 
        di::bind            
    );  
auto injector = di::make_injector(     
    di::bind.named(my).to(module)  
);      

auto object = injector.create>();
assert(dynamic_cast(object->up.get()));


Провайдеры


Примеры
«no throw»-провайдерТест
class heap_no_throw {                  
public: 
  template<                            
    class // interface                 
  , class T // implementation          
  , class TInit // direct()/uniform{}  
  , class TMemory // heap/stack        
  , class... TArgs>                    
  auto get(const TInit&                
         , const TMemory&              
         , TArgs&&... args)            
  const noexcept {                     
      return new (nothrow)             
        T{forward(args)...};    
  }     
};      
class my_provider : public di::config {
public: 
    auto provider() const noexcept {   
        return heap_no_throw{};        
    }   
};                             

// политика инжектора
auto injector = di::make_injector();
assert(0 == injector.create());
// глобальная политика
#define BOOST_DI_CFG my_provider
auto injector = di::make_injector();
assert(0 == injector.create());


Политики


Примеры
Ещё примеры
Определение политик конфигурации (дамп типов)Тест
class print_types_policy              
    : public di::config {             
public:                               
  auto policies() const noexcept {    
    return di::make_policies(         
      [](auto type){                  
         using T = decltype(type);    
         using arg = typename T::type;
         cout << typeid(arg).name()   
              << endl;                
      }                               
    ); 
  }    
};     

// политика инжектора
auto injector = di::make_injector();
injector.create(); // вывод: int
// глобальная политика
#define BOOST_DI_CFG my_policy
auto injector = di::make_injector();
injector.create(); // вывод: int


Определение политик конфигурации (развёрнутый дамп типов)Тест
class print_types_info_policy           
    : public di::config {               
public:  
  auto policies() const noexcept {      
    return di::make_policies(           
      [](auto type                      
       , auto dep                       
       , auto... ctor) {                
         using T = decltype(type);      
         using arg = typename T::type;  
         using arg_name =               
            typename T::name;           
         using D = decltype(dep);       
         using scope =                  
            typename D::scope;          
         using expected =               
            typename D::expected;       
         using given =                  
            typename D::given;          
         using name =                   
            typename D::name;           
         auto ctor_s = sizeof...(ctor); 
         cout << ctor_s                 
              << endl                   
              << typeid(arg).name()     
              << endl                   
              << typeid(arg_name).name()
              << endl                   
              << typeid(scope).name()   
              << endl                   
              << typeid(expected).name()
              << endl                   
              << typeid(given).name()   
              << endl                   
              << typeid(name).name()    
              << endl;                  
         ;                              
      }  
    );   
  }      
};       

// политика инжектора
auto injector = di::make_injector(
    di::bind
);
injector.create>();
// вывод:
    0 // ctor_size of impl1
    unique_ptr // ctor arg
    di::no_name // ctor arg name
    di::deduce // scope
    i1 // expected
    impl1 // given
    no_name // dependency
// глобальная политика
#define BOOST_DI_CFG my_policy
auto injector = di::make_injector(
    di::bind
);
injector.create>();
// вывод:
    0 // ctor_size of impl1
    unique_ptr // cotr arg
    di::no_name // ctor arg name
    di::deduce // scope
    i1 // expected
    impl1 // given
    no_name // dependency


Политика «может быть сконструирован»Тест
#include    
class all_must_be_bound_unless_int
    : public di::config {         
public:                           
  auto policies() const noexcept {
    using namespace di::policies; 
    using namespace               
        di::policies::operators;  
    return di::make_policies(     
      constructible(              
        is_same<_, int>{} ||      
        is_bound<_>{})            
    );                            
  }                               
}; 

// глобальная политика
#define BOOST_DI_CFG all_must_be_bound_unless_int
assert(0 == di::make_injector().create());
// di::make_injector().create(); // ошибка компиляции
assert(42.0 == make_injector(
                   di::bind.to(42.0)
               ).create()
);


Производительность на рантайме


Окружение
  • x86_64 Intel® Core(TM) i7-4770 CPU @ 3.40GHz GenuineIntel GNU/Linux
  • clang++3.4 -O2 / gdb -batch -ex 'file ./a.out' -ex 'disassemble main'


Создание типа без привязокAsm x86-64 (то же, что «return 0»)
int main() {                            
    auto injector = di::make_injector();
    return injector.create();      
}        

xor %eax,%eax
retq


Создание типа с привязкой объектаAsm x86-64 (то же, что «return 42»)
int main() {                          
    auto injector = di::make_injector(
        di::bind.to(42)          
    ); 
    return injector.create();    
}      

mov $0x2a,%eax
retq


Создание именованного типаAsm x86-64 (то же, что «return 42»)
auto my_int = []{};                   
struct c {                            
    BOOST_DI_INJECT(c                 
        , (named = my_int) int i)     
        : i(i)                        
    { }                               
    int i = 0;                        
};     
int main() {                          
  auto injector = di::make_injector(  
    di::bind.named(my_int).to(42)
  );   
  return injector.create().i;      
}      

mov $0x2a,%eax
retq


Создание привязки интерфейса к реализацииAsm x86-64 (то же, что «make_unique»)
int main() {                          
    auto injector = di::make_injector(
        di::bind           
    ); 
    auto ptr = injector.create<       
        unique_ptr                
    >();                              
    return ptr.get() != nullptr;      
}      

push   %rax
mov    $0x8,%edi
callq  0x4007b0 <_Znwm@plt>
movq   $0x400a30,(%rax)
mov    $0x8,%esi
mov    %rax,%rdi
callq  0x400960 <_ZdlPvm>
mov    $0x1,%eax
pop    %rdx
retq


Создание привязки интерфейса через модульAsm x86-64 (то же, что «make_unique»)
struct module {                       
    auto configure() const noexcept { 
        return di::make_injector(     
            di::bind       
        );                            
    }  
};     
int main() {                          
    auto injector = di::make_injector(
        module{}                      
    ); 
    auto ptr = injector.create<       
        unique_ptr                
    >();                              
    return ptr != nullptr;            
}

push   %rax
mov    $0x8,%edi
callq  0x4007b0 <_Znwm@plt>
movq   $0x400a10,(%rax)
mov    $0x8,%esi
mov    %rax,%rdi
callq  0x400960 <_ZdlPvm>
mov    $0x1,%eax
pop    %rdx
retq


Создание привязки интерфейса через открытый модульAsm x86-64
цена = вызов виртуального метода
struct module {                         
    di::injector configure() const {
        return di::make_injector(       
            di::bind         
        );                              
    }    
};       
int main() {                            
    auto injector = di::make_injector(  
        module{}                        
    );   
    auto ptr = injector.create<         
        unique_ptr                  
    >(); 
    return ptr != nullptr;              
}        

push   %rbp                               mov    (%rax),%ecx
push   %rbx                               lea    -0x1(%rcx),%edx
sub    $0x38,%rsp                         mov    %edx,(%rax)
lea    0x10(%rsp),%rdi                    cmp    $0x1,%ecx
lea    0x8(%rsp),%rsi                     jne    0x400bcd 
callq  0x400bf0 <_ZN5boost2di7exposed>    mov    (%rbx),%rax
mov    0x18(%rsp),%rdi                    mov    %rbx,%rdi
mov    (%rdi),%rax                        callq  *0x10(%rax)
lea    0x30(%rsp),%rsi                    lea    0xc(%rbx),%rax
callq  *0x10(%rax)                        mov    $0x0,%ecx
test   %rax,%rax                          test   %rcx,%rcx
setne  %bpl                               je     0x400bb8 
je     0x400b57                  mov    $0xffffffff,%ecx
mov    (%rax),%rcx                        lock   xadd %ecx,(%rax)
mov    %rax,%rdi                          mov    %ecx,0x30(%rsp)
callq  *0x8(%rcx)                         mov    0x30(%rsp),%ecx
mov    0x20(%rsp),%rbx                    jmp    0x400bbf 
test   %rbx,%rbx                          mov    (%rax),%ecx
je     0x400bcd                 lea    -0x1(%rcx),%edx
lea    0x8(%rbx),%rax                     mov    %edx,(%rax)
mov    $0x0,%ecx                          cmp    $0x1,%ecx
test   %rcx,%rcx                          jne    0x400bcd 
je     0x400b82                  mov    (%rbx),%rax
mov    $0xffffffff,%ecx                   mov    %rbx,%rdi
lock   xadd %ecx,(%rax)                   callq  *0x18(%rax)
mov    %ecx,0x30(%rsp)                    movzbl %bpl,%eax
mov    0x30(%rsp),%ecx                    add    $0x38,%rsp
jmp    0x400b89                 pop    %rbx
           pop    %rbp
-->        retq


Производительность на этапе компиляции


Пример

Окружение
  • x86_64 Intel® Core(TM) i7-4770 CPU @ 3.40GHz GenuineIntel GNU/Linux
  • clang++3.4 -O2


Заголовочный файл Boost.DIВремя [сек]
#include  
int main() { }          

0.165

Легенда
  • ctor = «голый» конструктор: c(int i, double d);
  • inject = внедрение в конструктор: BOOST_DI_INJECT(c, int i, double d);
  • all = все типы в модуле доступны: auto configure();
  • exposed = один тип в модуле доступен: di::injector configure();



  • 4248897537 объектов создано
  • 132 разных типа
  • 10 модулей



  • 1862039751439806464 объекта создано
  • 200 разных типов
  • 10 модулей



  • 5874638529236910091 объект создан
  • 310 разных типов
  • 100 разных интерфейсов
  • 10 модулей


Диагностические сообщения


Создание интерфейса без привязки к реализацииСообщение об ошибке
auto injector = di::make_injector();
injector.create>();  

error: allocating an object of abstract                  
class type 'i1' return new (nothrow)
T{forward(args)...};


Неоднозначность привязкиСообщение об ошибке
auto injector = di::make_injector(
    di::bind.to(42)          
  , di::bind.to(87)          
);
injector.create(); 

error: base class 'pair'
specified more than once as a direct
base class


Создание объекта без привязок
при политике, требующей их
Сообщение об ошибке
class all_bound : public di::config {
public: 
  auto policies() const noexcept {
    return di::make_policies(
      constructible(is_bound<_>{}) 
    );
  } 
};
auto injector =  di::make_injector();
injector.create();

error: static_assert failed                           
"Type T is not allowed"


Неверный синтаксис аннотаций
(NAMED вместо named)
Сообщение об ошибке
auto name = []{};                
struct c {                       
    BOOST_DI_INJECT(c            
        , (NAMED = name) int) { }
};                               
di::make_injector().create(); 

error: use of undeclared identifier
'named'


Конфигурация


МакросОписание
BOOST_DI_CFG_CTOR_LIMIT_SIZE            
----------------------------------------
BOOST_DI_CFG                            
----------------------------------------
BOOST_DI_INJECTOR                       

Лимит на максимальное количество разрешенных 
параметров конструктора [0-10, по-умолчанию 10]
----------------------------------------
Глобальная конфигурация, позволяющая 
переопределять провайдеры и политики
----------------------------------------
Имя, используемое внутри Boost.DI для определения 
свойств конструкторов
[по-умолчанию boost_di_injector__]


Похожие библиотеки




License: Boost Software License, Version 1.0
Nuance: the library is not yet included in Boost, but is only located in the " incubator ".

Also popular now: