dla*_*ila 8 c++ boost boost-optional gcc4.9 c++14
通常,当一个函数返回时,boost::optional
我看到很多人返回一个空括号{}
来指定一个空值,这样可以正常运行并且比返回时更短boost::none
.
我尝试做类似于清空a的操作boost::optional<int>
,但是当在右侧调用带有空括号的复制赋值运算符(或者很可能是移动赋值操作)时,空括号将转换为int,然后将该值赋值给可选的,所以我最终将变量设置为0而不是我期望的空值.这是一个示例https://godbolt.org/g/HiF92v,如果我尝试相同的,std::experimental::optional
我得到我期望的结果(只是用示例中的std :: experimental :: optional替换,你会看到指令成为mov eax, eax
).
另外,如果我尝试使用不同的模板参数进行boost可选(非整数类型),一些编译器会编译(使用我期望的行为,这里有一个示例http://cpp.sh/5j7n)而其他编译器则没有.因此,即使对于相同的lib,根据模板arg,行为也是不同的.
我想了解这里发生了什么,我知道这与我使用C++ 14功能的一个事实有关,这个库没有考虑到它进入设计.我读了boost/optional
标题,但我迷失了细节,我也尝试研究编译的代码,而没有内联类似的结果.
我正在使用gcc 4.9.2和-std = c ++ 14并且提升1.57.
顺便说一句:我知道我应该使用boost::optional::reset
或boost::none
,但我试图与其余代码库中的语义保持一致.
And*_*zej 10
要了解发生了什么,请首先考虑以下示例:
void fun(int) { puts("f int"); }
void fun(double) { puts("f double"); }
int main() {
fun({}); // error
}
Run Code Online (Sandbox Code Playgroud)
这会导致编译器错误,因为重载决策是不确定的:double
并且int
同样适合.但是,如果非标量类型发挥作用,情况就不同了:
struct Wrap{};
void fun(int) { puts("f(int)"); }
void fun(Wrap) { puts("f(Wrap)"); }
int main() {
fun({}); // ok: f(int) selected
}
Run Code Online (Sandbox Code Playgroud)
这是因为标量是更好的匹配.如果由于某种原因,我想要相同的两个重载,但同时我想fun({})
选择重载fun(Wrap)
,我可以稍微调整一下定义:
template <typename T>
std::enable_if_t<std::is_same<int, std::decay_t<T>>::value>
fun(T) { puts("f int"); }
void fun(Wrap) { puts("f(Wrap)"); }
Run Code Online (Sandbox Code Playgroud)
也就是说,fun(Wrap)
保持不变,但第一次重载现在是一个模板,它采取任何T
.但是enable_if
我们限制它,所以它只适用于类型int
.所以,这是一个非常"人为"的模板,但它确实起到了作用.如果我打电话:
fun(0); // picks fun(T)
Run Code Online (Sandbox Code Playgroud)
人工模板被选中.但如果我输入:
fun({}); // picks fun(Wrap)
Run Code Online (Sandbox Code Playgroud)
人工模板仍然是一个模板,因此在这种情况下从不考虑类型推导,并且唯一可见的重载是fun(Wrap)
,因此它被选中.
采用了相同的技巧std::optional<T>
:它没有来自的任务T
.相反,它有一个类似的人工分配模板,可以接受任何U
,但后来受到限制,以便T == U
.您可以在此处的参考实现中看到它.
boost::optional<T>
已经在C++ 11之前实现,没有意识到这个'重置习惯用法'.因此,它具有正常的分配T
,并且在T
恰好是标量的情况下,这种分配T
是优选的.因此差异.
鉴于这一切,我认为Boost.Optional有一个错误,它做的事情与之相反std::optional
.即使它在Boost.Optional中不可实现,它至少应该无法编译,以避免运行时意外.
归档时间: |
|
查看次数: |
2453 次 |
最近记录: |