boost-ext / di

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

const vector<T>& not compiling with shared_config #356

Closed marsermd closed 5 years ago

marsermd commented 6 years ago

Expected Behavior

Everything compiles as if there was no shared_config.

Actual Behavior

Compilation error:

c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2396): error C2440: 'return': cannot convert from 'TWrapper' to 'T'
1>        with
1>        [
1>            TWrapper=wrapper_t
1>        ]
1>        and
1>        [
1>            T=create_t
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2396): note: Reason: cannot convert from 'TWrapper' to 'const T'
1>        with
1>        [
1>            TWrapper=wrapper_t
1>        ]
1>        and
1>        [
1>            T=std::vector<std::shared_ptr<Bar>,std::allocator<std::shared_ptr<Bar>>>
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2396): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2396): note: while compiling class template member function 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t>::operator T(void) noexcept'
1>        with
1>        [
1>            T=create_t
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2224): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t>::operator T(void) noexcept' being compiled
1>        with
1>        [
1>            T=create_t
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2834): note: see reference to class template instantiation 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t>' being compiled
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2774): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t> boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>::create_successful_impl__<TIsRoot,const std::vector<std::shared_ptr<Bar>,std::allocator<_Ty>>&,boost::di::v1_1_0::no_name>(void) const' being compiled
1>        with
1>        [
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo,
1>            TIsRoot=boost::di::v1_1_0::aux::false_type,
1>            _Ty=std::shared_ptr<Bar>
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2224): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t> boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>::create_successful_impl<boost::di::v1_1_0::aux::false_type,const std::vector<std::shared_ptr<Bar>,std::allocator<_Ty>>&>(const boost::di::v1_1_0::aux::type<const std::vector<_Ty,std::allocator<_Ty>> &> &) const' being compiled
1>        with
1>        [
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo,
1>            _Ty=std::shared_ptr<Bar>
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(1791): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::any_type_1st_ref<TParent,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>>::operator const std::vector<std::shared_ptr<Bar>,std::allocator<_Ty>>&(void) const<std::vector<_Ty,std::allocator<_Ty>>,int,int>' being compiled
1>        with
1>        [
1>            TParent=Foo,
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo,
1>            _Ty=std::shared_ptr<Bar>
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(1792): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::any_type_1st_ref<TParent,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>>::operator const std::vector<std::shared_ptr<Bar>,std::allocator<_Ty>>&(void) const<std::vector<_Ty,std::allocator<_Ty>>,int,int>' being compiled
1>        with
1>        [
1>            TParent=Foo,
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo,
1>            _Ty=std::shared_ptr<Bar>
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2382): note: see reference to function template instantiation 'T boost::di::v1_1_0::providers::stack_over_heap::get<T,boost::di::v1_1_0::core::successful::any_type_1st_ref<TParent,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>>>(const boost::di::v1_1_0::type_traits::direct &,const boost::di::v1_1_0::type_traits::stack &,boost::di::v1_1_0::core::successful::any_type_1st_ref<TParent,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,TExpected,TExpected,TName,TPriority>>>> &&) const' being compiled
1>        with
1>        [
1>            T=Foo,
1>            TParent=Foo,
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            TExpected=Foo
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2834): note: see reference to class template instantiation 'boost::di::v1_1_0::core::successful::provider<ctor_t,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>>' being compiled
1>        with
1>        [
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2774): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t> boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>::create_successful_impl__<TIsRoot,T,boost::di::v1_1_0::no_name>(void) const' being compiled
1>        with
1>        [
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo,
1>            TIsRoot=boost::di::v1_1_0::aux::true_type
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\boost\di.hpp(2684): note: see reference to function template instantiation 'boost::di::v1_1_0::core::successful::wrapper<create_t,wrapper_t> boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>::create_successful_impl<boost::di::v1_1_0::aux::true_type,T>(const boost::di::v1_1_0::aux::type<T> &) const' being compiled
1>        with
1>        [
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            T=Foo,
1>            TExpected=Foo
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(55): note: see reference to function template instantiation 'T boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>::create<Foo,0>(void) const' being compiled
1>        with
1>        [
1>            T=Foo,
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            TExpected=Foo
1>        ]
1>c:\users\misch\source\repos\consoleapplication1\consoleapplication1\consoleapplication1.cpp(55): note: see reference to function template instantiation 'T boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,boost::di::v1_1_0::core::array<type>,boost::di::v1_1_0::core::array<type,Bar1,Bar2>,TName,TPriority>>,boost::di::v1_1_0::core::injector<TConfig,boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<>>,boost::di::v1_1_0::core::dependency<TScope,T,TExpected,TName,TPriority>>>::create<Foo,0>(void) const' being compiled
1>        with
1>        [
1>            T=Foo,
1>            TConfig=boost::di::v1_1_0::extension::shared_config,
1>            TScope=boost::di::v1_1_0::scopes::deduce,
1>            TName=boost::di::v1_1_0::no_name,
1>            TPriority=void,
1>            TExpected=Foo
1>        ]

Steps to Reproduce the Problem

Try to compile the following code:

#include <memory>

#include "Boost/di.hpp"
#include "Boost/extension/scopes/shared.hpp"

struct Bar
{
    virtual ~Bar() {}
};

struct Foo
{
    Foo(const std::vector<std::shared_ptr<Bar>>& bars){}
};

struct Bar1: Bar
{
};
struct Bar2: Bar
{
};

auto BuildBars()
{
    return boost::di::make_injector<boost::di::extension::shared_config>
    (
        boost::di::bind<Bar*[]>.to
        <
            Bar1,
            Bar2
        >()
    );
}

auto BuildFoo()
{
    return boost::di::make_injector<boost::di::extension::shared_config>
    (
        boost::di::bind<Foo>.to<Foo>()
    );
}

int main()
{
    auto injector = boost::di::make_injector<boost::di::extension::shared_config>
    (
        BuildBars(),
        BuildFoo()
    );
    injector.create<Foo>();
}

It will fail. But if you remove boost::di::extension::shared_config, everything will compile just fine.

Specifications

marsermd commented 6 years ago

Moreover, if you change Foo(const std::vector<std::shared_ptr<Bar>>& bars){} to Foo(std::vector<std::shared_ptr<Bar>> bars){} Everything compiles and seems to work in debug.

But in release only Bar2 is getting instantiated. After that, an invalid vector of size 2 is passed as an argument to Foo. That's a clear sign that there is an UB.

kanstantsin-chernik commented 5 years ago

I tested your code at VS 2017 and have no problem with Foo(std::vector<std::shared_ptr<Bar>> bars){}

kanstantsin-chernik commented 5 years ago

Reproducible with /c++17 flag

kanstantsin-chernik commented 5 years ago

I think we can close it. vector has valid objects. /std:c++17 is fixed and waited to be merged #365