c – boost可选和std :: experimental可选赋值之间的区别

前端之家收集整理的这篇文章主要介绍了c – boost可选和std :: experimental可选赋值之间的区别前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
通常,当一个函数返回boost :: optional时,我看到很多人返回一个空括号{}来指定一个空值,它运行正常并且比返回boost :: none更短.

我尝试做类似于清空boost :: optional< int>的事情,但是当在右侧调用带有空括号的复制赋值运算符(或者很可能是移动赋值op)时,空括号将转换为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,但我试图与其余代码库中的语义保持一致.

@H_403_13@解决方法
要了解发生了什么,请首先考虑以下示例:
void fun(int) { puts("f int"); }
void fun(double) { puts("f double"); }

int main() {
  fun({}); // error
}

这会导致编译器错误,因为重载决策是不确定的:double和int同样适合.但是,如果非标量类型发挥作用,情况就不同了:

struct Wrap{};
void fun(int) { puts("f(int)"); }
void fun(Wrap) { puts("f(Wrap)"); }

int main() {
  fun({}); // ok: f(int) selected
}

这是因为标量是更好的匹配.如果由于某种原因,我想要相同的两个重载,但同时我想有趣({})选择重载乐趣(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)"); }

也就是说,fun(Wrap)保持不变,但是第一个重载现在是一个接受任何T的模板.但是使用enable_if我们约束它,因此它只适用于int类型.所以,这是一个非常“人为”的模板,但它确实起到了作用.如果我打电话:

fun(0); // picks fun(T)

人工模板被选中.但如果我输入:

fun({}); // picks fun(Wrap)

人工模板仍然是模板,因此在这种情况下从不考虑类型推导,并且唯一可见的重载是有趣的(Wrap),因此它被选中.

在std :: optional< T>中使用相同的技巧:它没有来自T的赋值.相反,它有一个类似的人工赋值模板,它接受任何U,但后来被约束,因此T == U.你可以在参考实现here中看到它.

升压::可选< T>已经在C 11之前实现,没有意识到这个’重置成语’.因此,它具有来自T的正常分配,并且在T恰好是标量的情况下,来自T的该分配是优选的.因此差异.

鉴于这一切,我认为Boost.Optional有一个错误,它与std :: optional相反.即使它在Boost.Optional中不可实现,它至少应该无法编译,以避免运行时意外.

猜你在找的C&C++相关文章