8

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当用户尝试输入 a 时偷偷摸摸是0非常误导和危险的。

意图可能有点隐藏,因为我并没有真正推出一个myint课程,而且我真的没有一个class myclass几乎没有任何目的的课程。无论如何,我需要向函数发送 10 个左右的可选整数,而重复数据删除不起作用。(你可以想象我问了你的年龄、身高和财富,还有三个特殊的按钮可以检查你是否不想回答问题)


我发布了一个似乎在下面有效的答案(根据 Mooing 的 Duck & Ilonesmiz 建议构建,但更轻)。不过,我很高兴听到有关它的评论。

4

4 回答 4

3

不要让构造函数boost::optional取而代之,我会做这样的事情。

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

但是,当我考虑它时,我并不完全清楚您要实现的目标以及要避免发生的事情。会员的目的是什么optional

于 2013-03-06T18:09:16.677 回答
3

这比我喜欢的更丑,但它似乎解决了你的担忧。它的工作原理是将给定的参数完美地转发给myclass一对采用 anint或 a的函数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))
    {}
};

概念证明。现代编译器应该足够聪明,可以忽略副本,但这对于int.

于 2013-03-06T18:54:33.403 回答
1

我猜这个问题只对 optional 有意义int。一种解决方案可能是提供两个构造函数:

myclass() : content(boost::none) {}
myclass(myint input) : content(input) {}

确实,您失去了boost::optional...的优势。

于 2013-03-06T18:24:45.220 回答
1

这段代码(灵感来自 Ilonesmiz)似乎可以很好地完成这项工作,并且比 Mooing Duck 的方法要轻一些,但仍然使用神奇的模板技巧。

struct myprotectedclass {
    boost::optional<myint> content;

    template <class T>
    myprotectedclass(const T& a) :content(boost::optional<myint>(a)) {}


};

这是证明
当 C++ 看到 时0,它会认为“嗯,这可能是一个 int,但它可能是指向某个东西的指针!” (仅用于0,没有其他数字)但是如果你将它传递0给一个函数,它必须决定一个类型,所以它选择默认值int。而在原始版本中, a0被传递给期望 amyint或指针(boost::none_t是指针)的函数。0不是一个 myint,但它可以是一个指针,所以它选择了那个。

于 2013-03-07T13:50:12.687 回答