C++11 class in std::map as Value with private constructors
C++11 class in std::map as Value with private constructors
这是 class 的简化版本,它作为值存储在映射中,在 VS2008 中工作正常(请注意 所有 成员都是私有的):
class Value{
friend class FriendClass;
friend class std::map<std::string, Value>;
friend struct std::pair<const std::string, Value>;
friend struct std::pair<std::string, Value>;
Value() {..}
Value(Value const& other) {..}
... rest members...
};
代码(从 FriendClass 调用,因此可以访问私有构造函数):
FriendClass::func()
{
std::map<const std::string, Value> map;
map.insert(std::make_pair(std::string("x"), Value()));
}
这编译 w/o VS2008 中的任何错误,但在 VS2015/C++11:
上失败
file.cpp(178): error C2664: 'std::_Tree_iterator>>> std::_Tree>::insert(std::_Tree_const_iterator>>>,const std::pair &)': cannot convert argument 1 from 'std::pair' to 'std::pair &&'
with
[
_Kty=std::string,
_Ty=Value,
_Pr=std::less,
_Alloc=std::allocator>
]
and
[
_Kty=std::string,
_Ty=Value
]
file.cpp(178): note: Reason: cannot convert from 'std::pair' to 'std::pair'
with
[
_Kty=std::string,
_Ty=Value
]
file.cpp(178): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
如果我制作值复制构造函数public,它在 VS2015 中也可以正常编译。
但那是有目的的私有,并且只对 std::map 和 std::pair 可用。然而,在 C++11 中,额外的友元访问似乎也需要声明。这些是哪些?
谢谢。
我无法访问您提到的编译器,但这是我在 g++ 5.3 上看到的。
考虑以下基本相同的问题版本:
#include <map>
#include <utility>
class foo
{
friend std::pair<const int, foo>;
foo(const foo &other){}
public:
foo(){}
};
int main()
{
using map_t = std::map<int, foo>;
map_t m;
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
}
(默认的 ctor 是 public
,但这不是必需的,只是使示例更短。)
在main
中,注意两行
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
反转评论构建正常,但显示的版本没有:
/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int; <template-parameter-2-2> = void; _T1 = int; _T2 = foo]’:
/usr/include/c++/5/bits/stl_pair.h:281:72: required from ‘constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = foo; typename std::__decay_and_strip<_T2>::__type = foo; typename std::__decay_and_strip<_Tp>::__type = int]’
stuff.cpp:21:34: required from here
stuff.cpp:9:2: error: ‘foo::foo(const foo&)’ is private
foo(const foo &other){}
^
查看源代码std_pair.h
表明它确实在尝试调用复制构造函数。不幸的是,您 friend
编辑了 std::pair
,但没有 std::make_pair
。
emplace
版本没有这个问题,但我怀疑这是实现相关的。一般来说,如果你想要一个容器来存放一个完全不透明的class,我会建议你使用一个std::shared_ptr
的容器来存放它们。这允许您在自己的代码中完全指定哪些 function/class 可以 create/copy 对象,并且不对库的代码做任何假设。
这是 class 的简化版本,它作为值存储在映射中,在 VS2008 中工作正常(请注意 所有 成员都是私有的):
class Value{
friend class FriendClass;
friend class std::map<std::string, Value>;
friend struct std::pair<const std::string, Value>;
friend struct std::pair<std::string, Value>;
Value() {..}
Value(Value const& other) {..}
... rest members...
};
代码(从 FriendClass 调用,因此可以访问私有构造函数):
FriendClass::func()
{
std::map<const std::string, Value> map;
map.insert(std::make_pair(std::string("x"), Value()));
}
这编译 w/o VS2008 中的任何错误,但在 VS2015/C++11:
上失败file.cpp(178): error C2664: 'std::_Tree_iterator>>> std::_Tree>::insert(std::_Tree_const_iterator>>>,const std::pair &)': cannot convert argument 1 from 'std::pair' to 'std::pair &&' with [ _Kty=std::string, _Ty=Value, _Pr=std::less, _Alloc=std::allocator> ] and [ _Kty=std::string, _Ty=Value ] file.cpp(178): note: Reason: cannot convert from 'std::pair' to 'std::pair' with [ _Kty=std::string, _Ty=Value ] file.cpp(178): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
如果我制作值复制构造函数public,它在 VS2015 中也可以正常编译。
但那是有目的的私有,并且只对 std::map 和 std::pair 可用。然而,在 C++11 中,额外的友元访问似乎也需要声明。这些是哪些?
谢谢。
我无法访问您提到的编译器,但这是我在 g++ 5.3 上看到的。
考虑以下基本相同的问题版本:
#include <map>
#include <utility>
class foo
{
friend std::pair<const int, foo>;
foo(const foo &other){}
public:
foo(){}
};
int main()
{
using map_t = std::map<int, foo>;
map_t m;
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
}
(默认的 ctor 是 public
,但这不是必需的,只是使示例更短。)
在main
中,注意两行
m.insert(std::make_pair(2, foo()));
// m.emplace(2, foo());
反转评论构建正常,但显示的版本没有:
/usr/include/c++/5/bits/stl_pair.h: In instantiation of ‘constexpr std::pair<_T1, _T2>::pair(_U1&&, const _T2&) [with _U1 = int; <template-parameter-2-2> = void; _T1 = int; _T2 = foo]’:
/usr/include/c++/5/bits/stl_pair.h:281:72: required from ‘constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&) [with _T1 = int; _T2 = foo; typename std::__decay_and_strip<_T2>::__type = foo; typename std::__decay_and_strip<_Tp>::__type = int]’
stuff.cpp:21:34: required from here
stuff.cpp:9:2: error: ‘foo::foo(const foo&)’ is private
foo(const foo &other){}
^
查看源代码std_pair.h
表明它确实在尝试调用复制构造函数。不幸的是,您 friend
编辑了 std::pair
,但没有 std::make_pair
。
emplace
版本没有这个问题,但我怀疑这是实现相关的。一般来说,如果你想要一个容器来存放一个完全不透明的class,我会建议你使用一个std::shared_ptr
的容器来存放它们。这允许您在自己的代码中完全指定哪些 function/class 可以 create/copy 对象,并且不对库的代码做任何假设。