如何防止boost :: optional <t>错误地构造为0?</t>

时间:2013-03-06 18:00:40

标签: c++ boost boost-optional

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建议,但更轻)。不过,我很高兴听到有关它的评论。

4 个答案:

答案 0 :(得分:3)

不要让构造函数接受boost::optional我会做这样的事情。

struct myclass {
    boost::optional<myint> content;
    myclass () = default;
    explicit myclass(const myint& int_):content(int_){}
};

然而,当我在思考它时,我并不完全清楚你想要实现什么以及你想避免发生什么。 optional成员的目的是什么?

答案 1 :(得分:3)

这比我喜欢的更糟糕,但它似乎解决了你的担忧。它的工作原理是将赋予myclass的参数完美地转发给一对带有intboost::none_t的函数,绕过隐式的用户定义构造函数。这是有效的,因为0int更好地匹配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,但它可以是指针,所以它正在挑选那个。