boost::optional<T>
(1.51)提供了一种构建对我的用户非常危险的对象的方法,并且我想阻止它。假设我有自己的整数类,我想传递一个可选的这样的整数并将其存储在某个类中:
class myint {
public:
int m_a;
myint (int r_a) : m_a(r_a) {
}
};
struct myclass {
boost::optional<myint> content;
myclass (const boost::optional<myint>& arg) : content(arg) {
}
};
现在,以下是用户使用该类的方式:
myclass(myint(13)); //correct use
myclass(boost::none); //correct use
myclass(myint(0)); //correct use
myclass(0); //INCORRECT use, this easy typo
//equates boost::none which
//is not what the user meant
我想了解这里发生了什么,并防止这种行为。
有趣的是,
myclass(1); //does not compile
boost::none
对我的字段来说完全是一个有效值,但当用户尝试输入boost::none
时,0
偷偷摸摸是一种可怕的误导和危险。
意图可能有点隐藏,因为我并没有真正推出myint
类,而且我真的没有class myclass
几乎没有任何目的。无论如何,我需要向函数发送10个左右的可选ints,并且重复删除不起作用。 (你可以想象我问你的年龄,身高和财富,还有三个特殊的按钮来检查你是否不想回答问题)
我发布了一个似乎在下面工作的答案(根据Mooing的Duck&amp; Ilonesmiz建议,但更轻)。不过,我很高兴听到有关它的评论。
答案 0 :(得分:3)
不要让构造函数接受boost::optional
我会做这样的事情。
struct myclass {
boost::optional<myint> content;
myclass () = default;
explicit myclass(const myint& int_):content(int_){}
};
然而,当我在思考它时,我并不完全清楚你想要实现什么以及你想避免发生什么。 optional
成员的目的是什么?
答案 1 :(得分:3)
这比我喜欢的更糟糕,但它似乎解决了你的担忧。它的工作原理是将赋予myclass
的参数完美地转发给一对带有int
或boost::none_t
的函数,绕过隐式的用户定义构造函数。这是有效的,因为0
比int
更好地匹配boost::none_t
,并且隐含的用户定义构造函数是最差的匹配。
class myint {
public:
int m_a;
myint (int r_a) : m_a(r_a) {}
};
boost::optional<myint> myintctor(int arg) {return myint(arg);}
boost::optional<myint> myintctor(boost::none_t arg) {return arg;}
struct myclass {
boost::optional<myint> content0;
boost::optional<myint> content1;
boost::optional<myint> content2;
template<class T0, class T1, class T2>
myclass(const T0& a0, const T1& a1, const T2& a2)
:content0(myintctor(a0)), content1(myintctor(a1)), content2(myintctor(a2))
{}
};
Proof of concept。现代编译器应该足够聪明以避免复制,但这对于int
来说无关紧要。
答案 2 :(得分:1)
我猜这个问题只对可选int
有意义。一种解决方案可能是提供两个构造函数:
myclass() : content(boost::none) {}
myclass(myint input) : content(input) {}
确实你失去了boost::optional
...
答案 3 :(得分:1)
这段代码(灵感来自Ilonesmiz)似乎做得很好,比Mooing Duck的方法稍微轻一点,但仍然使用神奇的模板技巧。
struct myprotectedclass {
boost::optional<myint> content;
template <class T>
myprotectedclass(const T& a) :content(boost::optional<myint>(a)) {}
};
这是proof
当C ++看到0
时,它会认为“嗯,这可能是一个int,但它可能是指向某个东西的指针!” (仅适用于0
,没有其他数字)但是如果将0
传递给某个函数,它必须决定某个类型,因此它会选择默认值int
。然而,在原文中,0
被传递给期望myint
或指针(boost::none_t
是指针)的函数。 0
不是myint,但它可以是指针,所以它正在挑选那个。