您需要一个从 nullptr_t 转换为 Foo 的转换构造函数:
#include <functional>
#include <utility>
struct Foo {
Foo(std::function<void ()> f = nullptr) { }
Foo(std::nullptr_t) {}
};
typedef std::pair< void*, Foo > TestPair;
int main(void) {
Foo f(nullptr); // always works
//f = nullptr; // never works
TestPair p1(nullptr, static_cast< std::function<void()> >(nullptr)); // works
TestPair p2(nullptr, nullptr); // fails in some compilers
return 0;
}
MSVC 有时不需要复制构造函数来进行复制初始化。
Foo f = nullptr;
如果没有正确的转换构造函数,这将需要两个用户定义的转换,用于从 std::nullptr_t 到 Foo 的隐式转换(编译器不会这样做):从 std::nullptr_t 到 std::function<???>,然后到 Foo。对于其他情况,第一次转换可能在 c++17 下工作,但在这种情况下则不行。
std::pair 的构造函数将 nullptr 转发给 Foo 的构造函数,标准库的实现发生了一些变化。
抱歉耽搁了。我在令人敬畏的错误信息和 GNU 标准库的源代码中进行了一次小冒险。
下面是g++-6和g++-5中std::pair的转发构造函数:
// source code from /usr/include/c++/6/bits/stl_pari.h
template<typename _U1,
typename _U2,
typename
enable_if<
_MoveConstructiblePair<_T1, _T2, _U1, _U2>() &&
_ImplicitlyMoveConvertiblePair<_T1, _T2, _U1, _U2>(),
bool
>::type=true>
constexpr pair(_U1&& __x, _U2&& __y)
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
template<typename _U1,
typename _U2,
typename
enable_if<
_MoveConstructiblePair<_T1, _T2, _U1, _U2>() &&
!_ImplicitlyMoveConvertiblePair<_T1, _T2, _U1, _U2>(),
bool
>::type=false>
explicit constexpr pair(_U1&& __x, _U2&& __y)
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
// source code from /usr/include/c++/5/bits/stl_pari.h
template<class _U1,
class _U2,
class = typename
enable_if<
__and_<is_convertible<_U1, _T1>,is_convertible<_U2, _T2>>::value
>::type>
constexpr pair(_U1&& __x, _U2&& __y)
: first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { }
// error message from g++ 5.4
// This constructor failed us.
In file included from /usr/include/c++/5/bits/stl_algobase.h:64:0,
from /usr/include/c++/5/memory:62,
from main.cc:1:
/usr/include/c++/5/bits/stl_pair.h:144:12: note: candidate: template<class _U1, class _U2, class> constexpr std::pair<_T1, _T2>::pair(_U1&&, _U2&&)
constexpr pair(_U1&& __x, _U2&& __y)
^
/usr/include/c++/5/bits/stl_pair.h:144:12: note: template argument deduction/substitution failed:
/usr/include/c++/5/bits/stl_pair.h:141:38: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
template<class _U1, class _U2, class = typename
g++-5之所以不接受代码是因为std::nullptr_t和Foo是不可转换的。
g++-6 的_MoveConstructiblePair 大致可以告诉我们是否可以从另一个对象构造一个对象。在这种情况下,是可构造的。
结论:std::pair 的转发构造函数将他的要求从 Convertible 更改为 MoveConstructible。