boost-ext / di

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

boost::di can not create std::queue by default #287

Closed lisongmin closed 6 years ago

lisongmin commented 6 years ago

Expected Behavior

injector.create can create std::queue instance.

Actual Behavior

can not compile.

╰─ $ g++ -std=c++17 -I third/boost.di/include a.cpp
In file included from /usr/include/c++/7.2.1/queue:64:0,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_queue.h: In instantiation of ‘std::queue<_Tp, _Sequence>::queue(const _Alloc&) [with _Alloc = boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >; _Requires = void; _Tp = int; _Sequence = std::deque<int, std::allocator<int> >]’:
third/boost.di/include/boost/di.hpp:1843:12:   required from ‘auto boost::di::v1_1_0::providers::stack_over_heap::get(const boost::di::v1_1_0::type_traits::direct&, const boost::di::v1_1_0::type_traits::stack&, TArgs&& ...) const [with T = std::queue<int>; TArgs = {boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int, std::deque<int, std::allocator<int> > >, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >}]’
third/boost.di/include/boost/di.hpp:2350:108:   required from ‘auto boost::di::v1_1_0::core::successful::provider<boost::di::v1_1_0::aux::pair<T, boost::di::v1_1_0::aux::pair<TInitialization, TList<TCtor ...> > >, TInjector>::get(const TMemory&) const [with TMemory = boost::di::v1_1_0::type_traits::stack; T = std::queue<int>; TInjector = boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > >; TInitialization = boost::di::v1_1_0::type_traits::direct; TList = boost::di::v1_1_0::aux::type_list; TCtor = {boost::di::v1_1_0::core::any_type_1st_fwd<std::queue<int, std::deque<int, std::allocator<int> > > >}]’
third/boost.di/include/boost/di.hpp:1207:81:   required from ‘auto boost::di::v1_1_0::scopes::unique::scope< <template-parameter-1-1>, <template-parameter-1-2> >::create(const TProvider&) const [with T = std::queue<int>; <template-parameter-2-2> = boost::di::v1_1_0::no_name; TProvider = boost::di::v1_1_0::core::successful::provider<boost::di::v1_1_0::aux::pair<std::queue<int>, boost::di::v1_1_0::aux::pair<boost::di::v1_1_0::type_traits::direct, boost::di::v1_1_0::aux::type_list<boost::di::v1_1_0::core::any_type_1st_fwd<std::queue<int, std::deque<int, std::allocator<int> > > > > > >, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >; <template-parameter-1-1> = std::queue<int>; <template-parameter-1-2> = std::queue<int>]’
third/boost.di/include/boost/di.hpp:1253:56:   required from ‘auto boost::di::v1_1_0::scopes::deduce::scope<TExpected, TGiven>::create(const TProvider&) [with T = std::queue<int>; TName = boost::di::v1_1_0::no_name; TProvider = boost::di::v1_1_0::core::successful::provider<boost::di::v1_1_0::aux::pair<std::queue<int>, boost::di::v1_1_0::aux::pair<boost::di::v1_1_0::type_traits::direct, boost::di::v1_1_0::aux::type_list<boost::di::v1_1_0::core::any_type_1st_fwd<std::queue<int, std::deque<int, std::allocator<int> > > > > > >, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >; TExpected = std::queue<int>; TGiven = std::queue<int>]’
third/boost.di/include/boost/di.hpp:2800:115:   required from ‘auto boost::di::v1_1_0::core::injector<TConfig, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> >, TDeps ...>::create_successful_impl__() const [with TIsRoot = boost::di::v1_1_0::aux::integral_constant<bool, true>; T = std::queue<int>; TName = boost::di::v1_1_0::no_name; TConfig = boost::di::v1_1_0::config; TDeps = {}]’
third/boost.di/include/boost/di.hpp:2737:48:   required from ‘auto boost::di::v1_1_0::core::injector<TConfig, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> >, TDeps ...>::create_successful_impl(const boost::di::v1_1_0::aux::type<T>&) const [with TIsRoot = boost::di::v1_1_0::aux::integral_constant<bool, true>; T = std::queue<int>; TConfig = boost::di::v1_1_0::config; TDeps = {}]’
third/boost.di/include/boost/di.hpp:2647:74:   required from ‘T boost::di::v1_1_0::core::injector<TConfig, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> >, TDeps ...>::create() const [with T = std::queue<int>; typename boost::di::v1_1_0::aux::enable_if<boost::di::v1_1_0::core::injector<TConfig, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> >, TDeps ...>::is_creatable<T, boost::di::v1_1_0::no_name, boost::di::v1_1_0::aux::integral_constant<bool, true> >::value, int>::type <anonymous> = 0; TConfig = boost::di::v1_1_0::config; TDeps = {}]’
a.cpp:10:46:   required from here
/usr/include/c++/7.2.1/bits/stl_queue.h:166:9: error: no matching function for call to ‘std::deque<int, std::allocator<int> >::deque(const boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >&)’
  : c(__a) { }
         ^
In file included from /usr/include/c++/7.2.1/deque:64:0,
                 from /usr/include/c++/7.2.1/queue:60,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_deque.h:1023:2: note: candidate: template<class _InputIterator, class> std::deque<_Tp, _Alloc>::deque(_InputIterator, _InputIterator, const allocator_type&)
  deque(_InputIterator __first, _InputIterator __last,
  ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:1023:2: note:   template argument deduction/substitution failed:
In file included from /usr/include/c++/7.2.1/queue:64:0,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_queue.h:166:9: note:   candidate expects 3 arguments, 1 provided
  : c(__a) { }
         ^
In file included from /usr/include/c++/7.2.1/deque:64:0,
                 from /usr/include/c++/7.2.1/queue:60,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_deque.h:996:7: note: candidate: std::deque<_Tp, _Alloc>::deque(std::initializer_list<_Tp>, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::deque<_Tp, _Alloc>::allocator_type = std::allocator<int>] <near match>
       deque(initializer_list<value_type> __l,
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:996:7: note:   conversion of argument 1 would be ill-formed:
In file included from /usr/include/c++/7.2.1/queue:64:0,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_queue.h:166:9: error: passing ‘const boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >’ as ‘this’ argument discards qualifiers [-fpermissive]
  : c(__a) { }
         ^
In file included from a.cpp:2:0:
third/boost.di/include/boost/di.hpp:2164:3: note:   in call to ‘boost::di::v1_1_0::core::successful::any_type_1st<TParent, TInjector>::operator T() [with T = std::initializer_list<int>; <template-parameter-2-2> = int; TParent = std::queue<int>; TInjector = boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > >]’
   operator T() {
   ^~~~~~~~
In file included from /usr/include/c++/7.2.1/deque:64:0,
                 from /usr/include/c++/7.2.1/queue:60,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_deque.h:973:7: note: candidate: std::deque<_Tp, _Alloc>::deque(std::deque<_Tp, _Alloc>&&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::deque<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       deque(deque&& __x, const allocator_type& __a)
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:973:7: note:   candidate expects 2 arguments, 1 provided
/usr/include/c++/7.2.1/bits/stl_deque.h:966:7: note: candidate: std::deque<_Tp, _Alloc>::deque(const std::deque<_Tp, _Alloc>&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::deque<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       deque(const deque& __x, const allocator_type& __a)
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:966:7: note:   candidate expects 2 arguments, 1 provided
/usr/include/c++/7.2.1/bits/stl_deque.h:962:7: note: candidate: std::deque<_Tp, _Alloc>::deque(std::deque<_Tp, _Alloc>&&) [with _Tp = int; _Alloc = std::allocator<int>]
       deque(deque&& __x)
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:962:7: note:   no known conversion for argument 1 from ‘const boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >’ to ‘std::deque<int, std::allocator<int> >&&’
/usr/include/c++/7.2.1/bits/stl_deque.h:947:7: note: candidate: std::deque<_Tp, _Alloc>::deque(const std::deque<_Tp, _Alloc>&) [with _Tp = int; _Alloc = std::allocator<int>]
       deque(const deque& __x)
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:947:7: note:   no known conversion for argument 1 from ‘const boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >’ to ‘const std::deque<int, std::allocator<int> >&’
/usr/include/c++/7.2.1/bits/stl_deque.h:920:7: note: candidate: std::deque<_Tp, _Alloc>::deque(std::deque<_Tp, _Alloc>::size_type, const value_type&, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::deque<_Tp, _Alloc>::size_type = long unsigned int; std::deque<_Tp, _Alloc>::value_type = int; std::deque<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       deque(size_type __n, const value_type& __value,
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:920:7: note:   candidate expects 3 arguments, 1 provided
/usr/include/c++/7.2.1/bits/stl_deque.h:908:7: note: candidate: std::deque<_Tp, _Alloc>::deque(std::deque<_Tp, _Alloc>::size_type, const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::deque<_Tp, _Alloc>::size_type = long unsigned int; std::deque<_Tp, _Alloc>::allocator_type = std::allocator<int>] <near match>
       deque(size_type __n, const allocator_type& __a = allocator_type())
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:908:7: note:   conversion of argument 1 would be ill-formed:
In file included from /usr/include/c++/7.2.1/queue:64:0,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_queue.h:166:9: error: passing ‘const boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >’ as ‘this’ argument discards qualifiers [-fpermissive]
  : c(__a) { }
         ^
In file included from a.cpp:2:0:
third/boost.di/include/boost/di.hpp:2164:3: note:   in call to ‘boost::di::v1_1_0::core::successful::any_type_1st<TParent, TInjector>::operator T() [with T = long unsigned int; <template-parameter-2-2> = int; TParent = std::queue<int>; TInjector = boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > >]’
   operator T() {
   ^~~~~~~~
In file included from /usr/include/c++/7.2.1/deque:64:0,
                 from /usr/include/c++/7.2.1/queue:60,
                 from a.cpp:3:
/usr/include/c++/7.2.1/bits/stl_deque.h:895:7: note: candidate: std::deque<_Tp, _Alloc>::deque(const allocator_type&) [with _Tp = int; _Alloc = std::allocator<int>; std::deque<_Tp, _Alloc>::allocator_type = std::allocator<int>]
       deque(const allocator_type& __a)
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:895:7: note:   no known conversion for argument 1 from ‘const boost::di::v1_1_0::core::successful::any_type_1st<std::queue<int>, boost::di::v1_1_0::core::injector<boost::di::v1_1_0::config, boost::di::v1_1_0::core::pool<boost::di::v1_1_0::aux::type_list<> > > >’ to ‘const allocator_type& {aka const std::allocator<int>&}’
/usr/include/c++/7.2.1/bits/stl_deque.h:888:7: note: candidate: std::deque<_Tp, _Alloc>::deque() [with _Tp = int; _Alloc = std::allocator<int>]
       deque() : _Base() { }
       ^~~~~
/usr/include/c++/7.2.1/bits/stl_deque.h:888:7: note:   candidate expects 0 arguments, 1 provided

Steps to Reproduce the Problem

minimal code to reproduce this problem:

#include <boost/di.hpp>
#include <queue>

int main() {
  auto injector = boost::di::make_injector();
  injector.create<std::queue<int>>();
}

compile with g++ -std=c++17 option.

Specifications

kris-jusiak commented 6 years ago

Thanks, @lisongmin. The problem is that in the newest libstdc++ the queue constructor with the longest list of parameters is ambiguous; hence [Boost].DI can't deduce it properly.

It used to work fine in gcc-5.4 with older libstdc++ -> https://godbolt.org/g/vAbWWS

The easiest solution is to explicitly define what the queue ctor looks like by using ctor_traits

BOOST_DI_NAMESPACE_BEGIN
template <class T>
struct ctor_traits<std::queue<T>> {
  using boost_di_inject__ = di::inject<>; // use default ctor unless DI should inject something else
};
BOOST_DI_NAMESPACE_END

Full example here -> https://godbolt.org/g/QceQPi