测试如下:
class NotInit{};
NotInit NOT_INIT;
template<class T>
class Optional{
T value;
bool has_value;
public:
Optional() : value(), has_value(false){}
explicit Optional(NotInit):value(), has_value(false) {}
explicit Optional(T const & val):value(val), has_value(true){}
explicit Optional(Optional<T> const & other) {}
Optional& operator=(Optional<T> const & other){}
Optional& operator=(T const & other){}
};
enum X {
FIRST
};
struct Some {
Optional<X> member;
};
int main(int, char**){
Optional<X> const opt(NOT_INIT);
Some s = {NOT_INIT};
return 0;
}
Clang 3.4抱怨:
../st.cpp:31:12: error: no viable conversion from 'NotInit' to 'Optional<X>'
Some s = {NOT_INIT};
^~~~~~~~
1 error generated.
为什么它会抱怨结构初始化但是对于变量?为什么不选择具有适当参数的构造函数?
缺少什么重载,以便我可以使用它来初始化结构?
我无法使用提升,我不确定如果使用boost::optional
则不会出现此错误。
答案 0 :(得分:1)
您正在标记构造函数explicit
。因此,当您尝试使用大括号初始化列表初始化struct Some
时,您将触发隐式转换...
这可以防止:
class NotInit;
template <typename T>
class Optional {
// Here => Optional(NotInit) cannot be called implicitly
explicit Optional(NotInit):value(), has_value(false) {}
};
/* ... */
Some s = {NOT_INIT}; // Implicit call to Optional<X>(NotInit): whoops!
如果您删除explicit
,则可以保留:
Some s = {NOT_INIT};
如果您选择不这样做,那么您必须像这样实例化s
:
Some s = {Optional<X>(NOT_INIT)};
在任何情况下,您都必须删除复制构造函数上的explicit
关键字(必须执行复制,而不是&#34;虚拟&#34;构造函数)。
为什么?因为Optional<X>
对象是从NOT_INIT
构建的,所以必须复制到s.member
。
注意:你也可以提供一个移动构造函数,在这种情况下更合适,因为从NOT_INIT
转换得到的对象是一个右值。