Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multiple bindings broken with C++17 (VS 15.8) #350

Closed
scottmcnab opened this issue Sep 11, 2018 · 6 comments
Closed

multiple bindings broken with C++17 (VS 15.8) #350

scottmcnab opened this issue Sep 11, 2018 · 6 comments
Labels

Comments

@scottmcnab
Copy link

Expected Behavior

With Visual Studio 15.8.3 and /std:c++17 compiler flag defined, multiple bindings fails to compile. i.e.
code of the form:

auto injector = di::make_injector( di::bind<interface* []>().to<implementation1, implementation2>>() );

Which used to be able to be injected using:

struct example { example(std::vector<std::unique_ptr<interface>> v) {

This same code used to compile successfully on VS 15.5 with /std:c++17 flag set.

Actual Behavior

C:\git\boost-di\example>cl multiple_bindings.cpp -I../include/ /EHsc /std:c++17
Microsoft (R) C/C++ Optimizing Compiler Version 19.15.26726 for x64
Copyright (C) Microsoft Corporation. All rights reserved.

multiple_bindings.cpp
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\xmemory0(881): error C2280: 'std::unique_ptr<interface,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': attempting to reference a deleted function
with
[
_Ty=interface
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\memory(2337): note: see declaration of 'std::unique_ptr<interface,std::default_delete<_Ty>>::unique_ptr'
with
[
_Ty=interface
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\memory(2337): note: 'std::unique_ptr<interface,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)': function was explicitly deleted
with
[
_Ty=interface
]

C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\xmemory(163): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,_Ty&>(_Alloc &,_Objty *const ,_Ty &)' being compiled
with
[
_Alloc=std::allocator<std::unique_ptr<interface,std::default_delete>>,
_Ty=std::unique_ptr<interface,std::default_delete>,
_Objty=std::unique_ptr<interface,std::default_delete>
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\xmemory(164): note: see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,_Ty&>(_Alloc &,_Objty *const ,_Ty &)' being compiled
with
[
_Alloc=std::allocator<std::unique_ptr<interface,std::default_delete>>,
_Ty=std::unique_ptr<interface,std::default_delete>,
_Objty=std::unique_ptr<interface,std::default_delete>
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\xmemory(190): note: see reference to function template instantiation 'void std::_Uninitialized_backout_al<_FwdIt,_Alloc>::_Emplace_back<_Ty&>(_Ty &)' being compiled
with
[
_FwdIt=std::unique_ptr<interface,std::default_delete> ,
_Alloc=std::allocator<std::unique_ptr<interface,std::default_delete>>,
_Ty=std::unique_ptr<interface,std::default_delete>
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\xmemory(190): note: see reference to function template instantiation 'void std::_Uninitialized_backout_al<_FwdIt,_Alloc>::_Emplace_back<_Ty&>(_Ty &)' being compiled
with
[
_FwdIt=std::unique_ptr<interface,std::default_delete> ,
_Alloc=std::allocator<std::unique_ptr<interface,std::default_delete>>,
_Ty=std::unique_ptr<interface,std::default_delete>
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\xmemory(217): note: see reference to function template instantiation '_FwdIt std::_Uninitialized_copy_al_unchecked<_Ty
,_Ty
,_Alloc>(_InIt,const _InIt,const _FwdIt,_Alloc &,std::_General_ptr_iterator_tag,std::_Any_tag)' being compiled
with
[
_FwdIt=std::unique_ptr<interface,std::default_delete> *,
_Ty=std::unique_ptr<interface,std::default_delete>,
_Alloc=std::allocator<std::unique_ptr<interface,std::default_delete>>,
_InIt=std::unique_ptr<interface,std::default_delete> *
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\vector(1823): note: see reference to function template instantiation '_FwdIt std::_Uninitialized_copy<_Iter,std::unique_ptr<interface,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>(const _InIt,const _InIt,_FwdIt,_Alloc &)' being compiled
with
[
_FwdIt=std::unique_ptr<interface,std::default_delete> *,
_Iter=std::unique_ptr<interface,std::default_delete> *,
_Ty=interface,
_InIt=std::unique_ptr<interface,std::default_delete> *,
_Alloc=std::allocator<std::unique_ptr<interface,std::default_delete>>
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\vector(738): note: see reference to function template instantiation 'std::unique_ptr<interface,std::default_delete<_Ty>> std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::_Ucopy<std::unique_ptr<_Ty,std::default_delete<_Ty>>>(_Iter,_Iter,std::unique_ptr<_Ty,std::default_delete<_Ty>> *)' being compiled
with
[
_Ty=interface,
_Iter=std::unique_ptr<interface,std::default_delete> *
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\vector(738): note: see reference to function template instantiation 'std::unique_ptr<interface,std::default_delete<_Ty>> std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::_Ucopy<std::unique_ptr<_Ty,std::default_delete<_Ty>>>(_Iter,_Iter,std::unique_ptr<_Ty,std::default_delete<_Ty>> *)' being compiled
with
[
_Ty=interface,
_Iter=std::unique_ptr<interface,std::default_delete> *
]
C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.15.26726\include\vector(732): note: while compiling class template member function 'std::vector<std::unique_ptr<interface,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::vector(const std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &)'
with
[
_Ty=interface
]
../include/boost/di.hpp(1324): note: see reference to function template instantiation 'std::vector<std::unique_ptr<interface,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>::vector(const std::vector<std::unique_ptr<_Ty,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>> &)' being compiled
with
[
_Ty=interface
]
multiple_bindings.cpp(35): note: see reference to class template instantiation 'std::vector<std::unique_ptr<interface,std::default_delete<_Ty>>,std::allocator<std::unique_ptr<_Ty,std::default_delete<_Ty>>>>' being compiled
with
[
_Ty=interface
]

Steps to Reproduce the Problem

  1. Attempt to compile the example/multiple_bindings.cpp file using Visual Studio 15.8.3 with C++17 language enabled:

C:\git\boost-di\example>cl multiple_bindings.cpp -I../include/ /EHsc /std:c++17

Specifications

  • Version: latest git revision 57659cf (branch cpp14)
  • Platform: Windows (Visual Studio 15.8.3)

Any idea how to fix this? Thanks!

@Stannieman
Copy link

Stannieman commented Sep 17, 2018

How does your example constructor look like? Do you use std::move to move the parameter to the class variable?

EDIT: @scottmcnab forget about the question above. I can confirm kind of this behavior with similar code as yours (with latest di.hpp from master branch), except that I also get the infamous "creatable constraint not satisfied" error.
When I use shared_ptr instead of unique_ptr inside the vector the error about the deleted copy constructor goes away but the "creatable constraint not satisfied" error remains. So this could be 2 separate issues actually, but it's strange that the multiple_bindings.cpp does not have both errors. Perhaps because it's a struct and my example is a class?

#include "di.hpp"

#include <memory>
#include <vector>

namespace di = boost::di;

class IDependency { public: virtual ~IDependency() = default; };
class Dependency : public IDependency {};


class MyClass
{
public:
	MyClass(std::vector<std::shared_ptr<const IDependency>> dependencies);
};

MyClass::MyClass(std::vector<std::shared_ptr<const IDependency>> dependencies) {}


class Main { public: Main(); };

Main::Main() {
	const auto container = di::make_injector(
		di::bind<IDependency*[]>().to<Dependency>()
	);

	container.create<MyClass>();
}

I can confirm that this code works fine with MSVC 14.15 (from VS 15.8) when using /std:c++14 but not with /std:c++17. With MSVC 14.14 (from VS 15.7) this works in all cases. So there is some incompatibility with MSVC 14.15 when using C++17.

@scottmcnab
Copy link
Author

Yes @Stannieman I have seen a similar error before with std::unique_ptr and std::vector, when the std::unique_ptr is copied into a vector. This happens because unique_ptr can only be moved, not copied. std::shared_ptr does not have this issue, because it is safe to copy/assign a shared_ptr (it just temporarily increments the reference count).

The fact that this code works fine with /std:c++14 (and also with /std:c++17 in earlier Visual Studio 15.5 version compiler), suggests that for some reason the compiler is now choosing the wrong operator (eg. it selects copy assignment instead of move assignment), probably when it is constructing the std::vector<> of dependencies.

Unfortunately, I am not familiar with the internals of boost-di to know where to start investigating this, let alone what kind of syntactic tweaking would be required to convince the compiler to do the right thing!

If anyone could provide further insight here it would be most appreciated!

@Stannieman
Copy link

Stannieman commented Sep 18, 2018

I've opened an issue here also because at this point it's unclear if it's an issue with boost expecting non-standard behavior from the compiler, or if it's the new MSVC that's handling this case in a non-standard way.

@Stannieman
Copy link

Something is fixed and will be in next MSVC release, not sure which problem though but I think the creatable constraint not satisfied.

@marsermd
Copy link

marsermd commented Oct 18, 2018

For those who are waiting for VS update, A WORKAROUND:

Replace:
using value_type = typename T::value_type;
With:
using value_type = typename aux::identity<T>::type::value_type;

In struct array<T(), Ts...> : T defenition in di.hpp

@kanstantsin-chernik
Copy link
Collaborator

@marsermd thank you for the workaround. I am working on the update. The only policies_serialize left

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants