c++visual-c++c++17unique-ptrdllexport

What's the bug in this code, or what's the bug in MSVC?


Here's the snippet of code

#include<memory>
#include<unordered_map>

struct
__declspec(dllexport)
Foo {
    std::unordered_map<const int*, std::unique_ptr<int>> foo;
};

Foo foo();

which fails like this:

C:/data/msvc/14.39.33321-Pre/include\list(1299): error C2679: binary '=': no operator found which takes a right-hand operand of type 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' (or there is no acceptable conversion)
C:/data/msvc/14.39.33321-Pre/include\utility(315): note: could be 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
C:/data/msvc/14.39.33321-Pre/include\list(1299): note: 'std::pair<_Kty,_Ty> &std::pair<_Kty,_Ty>::operator =(volatile const std::pair<_Kty,_Ty> &)': cannot convert argument 2 from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty> &'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]
C:/data/msvc/14.39.33321-Pre/include\list(1299): note: Reason: cannot convert from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty>'
        with
        [
            _Kty=const int *,
            _Ty=std::unique_ptr<int,std::default_delete<int>>
        ]

... see linked example for complete error

I do see that the problem is the fact that std::unique_ptr is not copiable, as implied, for instance, by Reason: cannot convert from 'const std::pair<const int *const ,std::unique_ptr<int,std::default_delete<int>>>' to 'volatile const std::pair<_Kty,_Ty>', but why is the copyability required only on windows and only with the dllexport?


In the codebase where this has been extracted from, __declspec(dllexport) is the expansion of a macro that expands to different values on other platforms, e.g. __attribute__ ((visibility("default"))) on Linux, in which case the code compiles just fine.


Solution

  • MSVC wants to dllexport the copy constructor and the copy assignment operator for your struct (because you declared the whole struct as dllexport), and it seemingly tries to generate default implementations for them, even though they should be deleted. I would say it's an MSVC bug. Explicitly deleting them solves the problem demo.