Boost.DI: внедрение зависимости в С++
«Не звони нам. Мы позвоним тебе сами.» — принцип Голливуда
Внедрение зависимости (Dependency Injection — DI) означает передачу (внедрение) одной или более зависимости какому-либо объекту (клиенту, компоненту) таким образом, что после внедрения эта зависимость становится частью состояния объекта. Это немного напоминает паттерн проектирования Стратегия, с той лишь разницей, что стратегия задаётся лишь однажды — в конструкторе. DI позволяет создавать более слабо-связанную архитектуру приложения, которая лучше поддаётся поддержке и тестированию.
Итак, ещё раз плюсы:
- Уменьшает связность компонент (отделяет бизнес-логику от создания объекта)
- Позволяет писать более поддерживаемый код (в одни и те же объекты мы легко можем внедрять разные зависимости)
- Позволяет писать более тестируемый код (мы можем легче использовать стабы и моки)
Без внедрения зависимости |
С внедрением зависимости |
class example {
public:
example()
: logic_(new logic{})
, logger_(
logger_factory::create()
)
{ }
int run() const;
private:
shared_ptr<ilogic> logic_;
shared_ptr<ilogger> logger_;
};
|
class example {
public:
example(shared_ptr<ilogic> logic
, shared_ptr<ilogger> logger)
: logic_(logic), logger_(logger)
{ }
int run() const;
private:
shared_ptr<ilogic> logic_;
shared_ptr<ilogger> logger_;
};
|
Boost.DI это библиотека для реализации внедрения зависимости в С++. Для её использования нужно лишь включить в свой код один заголовочный файл. Цель библиотеки — упростить создание объектов с помощью автоматического внедрения зависимостей:
- Уменьшение количества «узких мест» в коде — никаких лишних фабрик, никакого создания объектов лишь в определённом порядке
- Упрощение поддержки кода — изменение сигнатуры конструктора не повлияет на конфигурацию DI
- Упрощение тестирование — автоматическая инъекция моков
- Более хороший контроль над тем, что и когда создаётся
- Лучшее понимание кода в плане иерархии объектов
Ручное внедрение зависимости |
Boost.DI |
int main() {
/*boilerplate code*/
auto logic = make_shared<logic>();
auto logger = make_shared<logger>();
return example{logic, logger}.run();
}
|
int main() {
auto injector = di::make_injector(
di::bind<ilogic, logic>
, di::bind<ilogger, logger>
);
return injector.create<example>().run();
}
|
Ещё раз — зачем использовать внедрение зависимости
С чего начать?
- Возьмите компилятор с поддержкой С++14 (Clang-3.4+, GCC-5.0+). Библиотека Boost не требуется
- Прочитайте этот документ
- Прочитайте учебник [3]
- Прочитайте документацию [4]
А вообще-то всё, что вам необходимо для работы с библиотекой, этой файл di.hpp [5]
// main.cpp
#include "di.hpp"
int main() { }
$CXX -std=c++1y -I. main.cpp
Давайте предположим, что все примеры ниже включают boost/di.hpp и определяют пространство имён di как алиас boost::di.
#include <boost/di.hpp>
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 { } };
Создание пустого инжектора |
Тест |
auto injector = di::make_injector();
|
assert(0 == injector.create<int>());
|
Примеры [8]
Ещё примеры [9]
Привязка интерфейса к реализации |
Тест |
auto injector = di::make_injector(di::bind<i1, impl1>);
|
auto object = injector.create<unique_ptr<i1>>();
assert(dynamic_cast<impl1*>(object.get()));
|
Привязка нескольких интерфейсов к одной реализации |
Тест |
auto injector = di::make_injector(di::bind<di::any_of<i1, i2>, impl>);
|
auto object1 = injector.create<shared_ptr<i1>>();
auto object2 = injector.create<shared_ptr<i2>>();
assert(dynamic_cast<impl*>(object1.get()));
assert(dynamic_cast<impl*>(object2.get()));
|
Привязка типа к значению, вычисляемому на этапе компиляции |
Тест |
template<int N> using int_ = integral_constant<int, N>;
auto injector = di::make_injector(di::bind<int, int_<42>>);
|
assert(42 == injector.create<int>());
|
Привязка типа к значению |
Тест |
auto injector = di::make_injector(di::bind<int>.to(42));
|
assert(42 == injector.create<int>());
|
Примеры [11]
Ещё примеры [12]
Внедрение через обычный конструктор |
Тест |
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<int>.to(42)
, di::bind<double>.to(87.0)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87.0 == object.d);
|
Внедрение через аггрегацию |
Тест |
struct c {
int a = 0;
double d = 0.0;
};
auto injector = di::make_injector(
di::bind<int>.to(42)
, di::bind<double>.to(87.0)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87.0 == object.d);
|
Внедрение через конструктор при наличии
нескольких конструкторов (будет выбран тот, у которого
наибольшее число параметров) |
Тест |
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<int>.to(42)
, di::bind<double>.to(87.0)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87.0 == object.d);
|
Внедрение через конструктор при наличии вариантов
выбора (использование BOOST_DI_INJECT)
|
Тест |
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<int>.to(42)
, di::bind<double>.to(87.0)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87.0 == object.d);
|
Внедрение через конструктор при наличии вариантов
выбора (использование BOOST_DI_INJECT_TRAITS) |
Тест |
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<int>.to(42)
, di::bind<double>.to(87.0)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87.0 == object.d);
|
Внедрение через конструктор при наличии вариантов
выбора (использование di::ctor_traits) |
Тест |
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<c> {
BOOST_DI_INJECT_TRAITS(int, double);
};
}} // boost::di
auto injector = di::make_injector(
di::bind<int>.to(42)
, di::bind<double>.to(87.0)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87.0 == object.d);
|
Примеры [14]
Внедрение через аннотированные конструкторы |
Тест |
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<int>.named(int1).to(42)
, di::bind<int>.named(int2).to(87)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87 == object.b);
|
Внедрение через аннотированные конструкторы с
использованием именованных параметров |
Тест |
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<int>.named(n1).to(42)
, di::bind<int>.named(n2).to(87)
, di::bind<string>.named(n1).to("str")
);
|
auto object = injector.create<c>();
assert(42 == object.i1);
assert(42 == object.i2);
assert(87 == object.i3);
assert(0 == object.i4);
assert("str" == c.s);
|
Внедрение через аннотированные конструкторы с
вынесением реализации конструктора |
Тест |
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<int>.named(int1).to(42)
, di::bind<int>.named(int2).to(87)
);
|
auto object = injector.create<c>();
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<c> {
BOOST_DI_INJECT_TRAITS(
(named = int1) int
, (named = int2) int);
};
}} // boost::di
auto injector = di::make_injector(
di::bind<int>.named(int1).to(42)
, di::bind<int>.named(int2).to(87)
);
|
auto object = injector.create<c>();
assert(42 == object.a);
assert(87 == object.b);
|
Примеры [16]
Ещё примеры [17]
Вывод области видимости (по-умолчанию) |
Тест |
struct c {
shared_ptr<i1> sp; /*singleton*/
unique_ptr<i2> up; /*unique*/
int& i; /*external*/
double d; /*unique*/
};
auto i = 42;
auto injector = di::make_injector(
di::bind<i1, impl1>
, di::bind<i2, impl2>
, di::bind<int>.to(ref(i))
, di::bind<double>.to(87.0)
);
|
auto object1 = injector.create<unique_ptr<c>>();
auto object2 = injector.create<unique_ptr<c>>();
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);
|
Тип |
Выведенная область видимости |
T |
unique |
T& |
ошибка — должен быть связан как external |
const T& |
unique (временный) |
T* |
unique (передача владения) |
const T* |
unique (передача владения) |
T&& |
unique |
unique_ptr |
unique |
shared_ptr |
singleton |
weak_ptr |
singleton |
Уникальная область видимости |
Тест |
auto injector = di::make_injector(
di::bind<i1, impl1>.in(di::unique)
);
|
assert(injector.create<shared_ptr<i1>>()
!=
injector.create<shared_ptr<i1>>()
| );
|
Разделяемая область видимости (в пределах потока) |
Тест |
auto injector = di::make_injector(
di::bind<i1, impl1>.in(di::shared)
);
|
assert(injector.create<shared_ptr<i1>>()
==
injector.create<shared_ptr<i1>>()
| );
|
Синглтон (разделяем между потоками) |
Тест |
auto injector = di::make_injector(
di::bind<i1, impl1>.in(di::singleton)
);
|
assert(injector.create<shared_ptr<i1>>()
==
injector.create<shared_ptr<i1>>());
|
Область видимости сессии |
Тест |
auto my_session = []{};
auto injector = di::make_injector(
di::bind<i1, impl1>.in(
di::session(my_session)
)
);
|
assert(nullptr == injector.create<shared_ptr<i1>>());
injector.call(di::session_entry(my_session));
assert(injector.create<shared_ptr<i1>>()
==
injector.create<shared_ptr<i1>>());
injector.call(di::session_exit(my_session));
assert(nullptr == injector.create<shared_ptr<i1>>());
|
Внешняя область видимости |
Тест |
auto l = 42l;
auto b = false;
auto injector = di::make_injector(
di::bind<int, int_<41>>
, di::bind<int>.to(42)
, di::bind<i1>.to(make_shared<impl>())
, di::bind<long>.to(ref(l))
, di::bind<short>.to([]{return 87;})
, di::bind<i2>.to(
[&](const auto& injector)
-> shared_ptr<i2> {
if (b) {
return injector.template
create<
shared_ptr<impl2>>();
}
return nullptr;
}
)
);
|
assert(42 == injector.create<int>()); // external has priority
assert(injector.create<shared_ptr<i1>>()
==
injector.create<shared_ptr<i1>>()
);
assert(l == injector.create<long&>());
assert(&l == &injector.create<long&>());
assert(87 == injector.create<short>());
{
auto object = injector.create<shared_ptr<i2>>();
assert(nullptr == object);
}
{
b = true;
auto object = injector.create<shared_ptr<i2>>();
assert(dynamic_cast<impl2*>(object.get()));
}
|
Специальная область видимости |
Тест |
struct custom_scope {
static constexpr
auto priority = false;
template<class TExpected, class>
struct scope {
template<class T, class TProvider>
auto create(const TProvider& pr) {
return
shared_ptr<TExpected>{pr.get()};
}
};
};
auto injector = di::make_injector(
di::bind<i1, impl1>.in(custom_scope{})
);
|
assert(injector.create<shared_ptr<i1>>()
!=
injector.create<shared_ptr<i1>>()
);
|
Примеры [19]
Модуль |
Тест |
struct c {
c(unique_ptr<i1> i1
, unique_ptr<i2> i2
, int i) : i1(move(i1))
, i2(move(i2)), i(i)
{ }
unique_ptr<i1> i1;
unique_ptr<i2> i2;
int i = 0;
};
struct module1 {
auto configure() const noexcept {
return di::make_injector(
di::bind<i1, impl1>
, di::bind<int>.to(42)
);
}
};
struct module2 {
auto configure() const noexcept {
return di::make_injector(
di::bind<i2, impl2>
);
};
};
auto injector = di::make_injector(
module1{}, module2{}
);
|
auto object = injector.create<unique_ptr<c>>();
assert(dynamic_cast<impl1*>(object->i1.get()));
assert(dynamic_cast<impl2*>(object->i2.get()));
assert(42 == object->i);
auto up1 = injector.create<unique_ptr<i1>>();
assert(dynamic_cast<impl1*>(up1.get()));
auto up2 = injector.create<unique_ptr<i2>>();
assert(dynamic_cast<impl2*>(up2.get()));
|
Модуль, открывающий тип |
Тест |
struct c {
c(shared_ptr<i1> i1
, shared_ptr<i2> i2
, int i) : i1(i1), i2(i2), i(i)
{ }
shared_ptr<i1> i1;
shared_ptr<i2> i2;
int i = 0;
};
struct module {
di::injector<c> configure()
const noexcept;
int i = 0;
};
di::injector<c> // открывает c
module::configure() const noexcept {
return di::make_injector(
di::bind<i1, impl1>
, di::bind<i2, impl2>
, di::bind<int>.to(i)
);
}
auto injector = di::make_injector(
module{42}
);
|
auto object = injector.create<c>();
assert(dynamic_cast<impl1*>(object.i1.get()));
assert(dynamic_cast<impl2*>(object.i2.get()));
assert(42 == object.i);
// injector.create<unique_ptr<i1>>() // ошибка компиляции
// injector.create<unique_ptr<i2>>() // ошибка компиляции
|
Модуль, открывающий несколько типов |
Тест |
struct module {
di::injector<i1, i2> configure()
const noexcept;
int i = 0;
};
di::injector<i1, i2> // открывает i1, i2
module::configure() const noexcept {
return di::make_injector(
di::bind<i1, impl1>
, di::bind<i2, impl2>
);
}
auto injector = di::make_injector(
module{}
);
|
auto up1 = injector.create<unique_ptr<i1>>();
assert(dynamic_cast<impl1*>(up1.get()));
auto up2 = injector.create<unique_ptr<i2>>();
assert(dynamic_cast<impl2*>(up2.get()));
|
Модуль открытого типа с аннотацией |
Тест |
auto my = []{};
struct c {
BOOST_DI_INJECT(c
, (named = my) unique_ptr<i1> up)
: up(up)
{ }
unique_ptr<i1> up;
};
di::injector<i1> module =
di::make_injector(
di::bind<i1, impl1>
);
auto injector = di::make_injector(
di::bind<i1>.named(my).to(module)
);
|
auto object = injector.create<unique_ptr<c>>();
assert(dynamic_cast<impl1*>(object->up.get()));
|
Примеры [21]
«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<TArgs>(args)...};
}
};
class my_provider : public di::config {
public:
auto provider() const noexcept {
return heap_no_throw{};
}
};
|
// политика инжектора
auto injector = di::make_injector<my_provider>();
assert(0 == injector.create<int>());
// глобальная политика
#define BOOST_DI_CFG my_provider
auto injector = di::make_injector();
assert(0 == injector.create<int>());
|
Примеры [23]
Ещё примеры [24]
Определение политик конфигурации (дамп типов) |
Тест |
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<print_types_policy>();
injector.create<int>(); // вывод: int
// глобальная политика
#define BOOST_DI_CFG my_policy
auto injector = di::make_injector();
injector.create<int>(); // вывод: 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<print_types_info_policy>(
di::bind<i1, impl1>
);
injector.create<unique_ptr<i1>>();
// вывод:
0 // ctor_size of impl1
unique_ptr<i1> // 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<i1, impl1>
);
injector.create<unique_ptr<i1>>();
// вывод:
0 // ctor_size of impl1
unique_ptr<i1> // cotr arg
di::no_name // ctor arg name
di::deduce // scope
i1 // expected
impl1 // given
no_name // dependency
|
Политика «может быть сконструирован» |
Тест |
#include <boost/di/
policies/constructible.hpp>
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<int>());
// di::make_injector().create<double>(); // ошибка компиляции
assert(42.0 == make_injector(
di::bind<double>.to(42.0)
).create<double>()
);
|
Окружение
- 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<int>();
}
|
xor %eax,%eax
retq
|
Создание типа с привязкой объекта |
Asm x86-64 (то же, что «return 42») |
int main() {
auto injector = di::make_injector(
di::bind<int>.to(42)
);
return injector.create<int>();
}
|
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<int>.named(my_int).to(42)
);
return injector.create<c>().i;
}
|
mov $0x2a,%eax
retq
|
Создание привязки интерфейса к реализации |
Asm x86-64 (то же, что «make_unique») |
int main() {
auto injector = di::make_injector(
di::bind<i1, impl1>
);
auto ptr = injector.create<
unique_ptr<i1>
>();
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<i1, impl1>
);
}
};
int main() {
auto injector = di::make_injector(
module{}
);
auto ptr = injector.create<
unique_ptr<i1>
>();
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<i1> configure() const {
return di::make_injector(
di::bind<i1, impl1>
);
}
};
int main() {
auto injector = di::make_injector(
module{}
);
auto ptr = injector.create<
unique_ptr<i1>
>();
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 <main+173>
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 <main+152>
je 0x400b57 <main+55> 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 <main+159>
test %rbx,%rbx mov (%rax),%ecx
je 0x400bcd <main+173> lea -0x1(%rcx),%edx
lea 0x8(%rbx),%rax mov %edx,(%rax)
mov $0x0,%ecx cmp $0x1,%ecx
test %rcx,%rcx jne 0x400bcd <main+173>
je 0x400b82 <main+98> 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 <main+105> pop %rbx
pop %rbp
--> retq
|
Пример [26]
Окружение
- x86_64 Intel® Core(TM) i7-4770 CPU @ 3.40GHz GenuineIntel GNU/Linux
- clang++3.4 -O2
Заголовочный файл Boost.DI |
Время [сек] |
#include <boost/di.hpp>
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<c> configure();
- 4248897537 объектов создано
- 132 разных типа
- 10 модулей
- 1862039751439806464 объекта создано
- 200 разных типов
- 10 модулей
- 5874638529236910091 объект создан
- 310 разных типов
- 100 разных интерфейсов
- 10 модулей
Создание интерфейса без привязки к реализации |
Сообщение об ошибке |
auto injector = di::make_injector();
injector.create<unique_ptr<i1>>();
|
error: allocating an object of abstract
class type 'i1' return new (nothrow)
T{forward<TArgs>(args)...};
|
Неоднозначность привязки |
Сообщение об ошибке |
auto injector = di::make_injector(
di::bind<int>.to(42)
, di::bind<int>.to(87)
);
injector.create<int>();
|
error: base class 'pair<int, no_name>'
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<all_bound>();
injector.create<int>();
|
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<c>();
|
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__]
|
Похожие библиотеки
Лицензия: Boost Software License, Version 1.0 [34]
Нюанс: библиотека пока не входит в Boost, а лишь находится в "инкубаторе [35]".
Автор: tangro
Источник [36]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/80889
Ссылки в тексте:
[1] Мотивация: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/motivation.html
[2] Логическое обоснование: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/rationale.html
[3] учебник: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/tutorial.html
[4] документацию: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html
[5] di.hpp: https://raw.githubusercontent.com/krzysztof-jusiak/di/cpp14/include/boost/di.hpp
[6] Инжектор: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/injector.html
[7] Привязки: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/bindings.html
[8] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/bindings.cpp
[9] Ещё примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/dynamic_bindings.cpp
[10] Внедрение: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/injections.html
[11] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/constructor_injection.cpp
[12] Ещё примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/constructor_signature.cpp
[13] Аннотации: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/annotations.html
[14] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/annotations.cpp
[15] Области видимости: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/scopes.html
[16] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/deduce_scope.cpp
[17] Ещё примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/custom_scope.cpp
[18] Модули: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/modules.html
[19] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/modules.cpp
[20] Провайдеры: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/providers.html
[21] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/custom_provider.cpp
[22] Политики: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/concepts/policies.html
[23] Примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/types_dumper.cpp
[24] Ещё примеры: https://github.com/krzysztof-jusiak/di/blob/cpp14/example/custom_policy.cpp
[25] Производительность на рантайме: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/performance.html
[26] Пример: https://github.com/krzysztof-jusiak/di/blob/cpp14/test/pt/di.cpp
[27] Диагностические сообщения: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/diagnostic_messages.html
[28] Конфигурация: http://krzysztof-jusiak.github.io/di/cpp14/boost/libs/di/doc/html/di/overview.html#di.overview.configuration
[29] dicpp: https://bitbucket.org/cheez/dicpp
[30] Fruit: https://github.com/google/fruit
[31] Dagger 2: https://github.com/google/dagger
[32] Guice: https://github.com/google/guice
[33] Ninject: http://www.ninject.org/
[34] Boost Software License, Version 1.0: http://www.boost.org/LICENSE_1_0.txt
[35] инкубаторе: http://rrsd.com/blincubator.com/alphabetically/
[36] Источник: http://habrahabr.ru/post/248879/
Нажмите здесь для печати.