【问题标题】:Implicit conversion to explicit bool-types for sorting containers?隐式转换为用于排序容器的显式布尔类型?
【发布时间】:2011-11-04 17:44:00
【问题描述】:

我正在为演员操作员使用新的explicit。如果你写类似

struct Data {
    explicit operator string(); 
};

不可能意外地将Data 转换为string。目标数据类型bool 是一个例外:在某些情况下,即使标记为explicit,也允许隐式转换——上下文转换。因此,您可以在 if(...) 中使用此数据类型,例如:

struct Ok {
    explicit operator bool(); // allowed in if(...) anyway
};

“25.4.(2) 排序和相关操作” 段落似乎也允许像set 一样的标准容器Compare 函子这样做。但是我对 gcc-4.7.0 的尝试失败了,我注意到这是我的误解还是 gcc 中的错误?

#include <set>

struct YesNo { // Return value type of Comperator
    int val_;
    explicit YesNo(int y) : val_{y} {}
    /* explicit */ operator bool() { return val_!=0; }
};

static const YesNo yes{1};
static const YesNo no{0};

struct LessYesNo {  // Comperator with special return values
    YesNo operator()(int a, int b) const {
        return a<b ? yes : no;
    }
};

int main() {
    std::set<int,LessYesNo> data {2,3,4,1,2};
}

如果在operator bool() 之前没有explicit,则示例编译。而我对“25.4.(2)”的理解是,这也应该编译with`explicit.

我是否正确理解了 setexplicit bool 转换应该有效的标准? 那么这可能是 gcc 中的错误,还是我理解错误?

【问题讨论】:

  • 我同意您对 FWIW 标准的阅读。你从 gcc 得到什么错误?
  • 我同意它似乎是这样解释的,所以它可能还没有在 gcc 中实现(当编译器仍然正在编写时,我对谈论错误持谨慎态度)。

标签: c++ c++11 boolean explicit


【解决方案1】:

我对标准的解读有点不同—— 第 25.4 节处理排序算法而不是排序容器; 25.4.(1) 中建立的上下文意味着 25.4.(2) 中指定的比较对象的属性适用于 25.4 中的算法,而不适用于已排序的容器

1 25.4 中的所有操作都有两个版本:一个需要一个 比较类型的函数对象和一个使用运算符的对象。

2 Compare 是一个函数对象类型 (20.8)。的返回值 函数调用操作应用于比较类型的对象,当 上下文转换为 bool (4),如果第一个参数返回 true 的调用小于第二个,否则为假。比较比较 始终用于假设排序关系的算法。这是 假设 comp 不会通过 取消引用的迭代器。

我不知道您的示例是否应该有效,但我认为第 25.4 节不适用于此处。

使用向量和 std::sort 进行快速测试:

#include <list>
#include <algorithm>

struct YesNo { // Return value type of Comperator
    int val_;
    explicit YesNo(int y) : val_{y} {}
    explicit operator bool() { return val_!=0; }
};

static const YesNo yes{1};
static const YesNo no{0};

struct LessYesNo {  // Comperator with special return values
    YesNo operator()(int a, int b) const {
        return a<b ? yes : no;
    }
};

int main() {
    std::vector<int> data {2,3,4,1,2};
    std::sort(std::begin(data), std::end(data), LessYesNo());
}

编辑:

关联容器的比较参数根据第 25.4 节定义:

1 关联容器提供基于键的快速数据检索。该库提供四种基本类型的关联容器:set、multiset、map 和 multimap。

2 每个关联容器都在 Key 和一个排序关系上进行参数化比较 对 Key 的元素产生严格的弱排序 (25.4)。此外,map 和 multimap 将任意类型 T 与 Key 相关联。 Compare 类型的对象称为容器的比较对象。

据我所知,23. 对 Compare 的类型没有其他条件,因此假设满足 25.4 约束的类型同样适用似乎是合理的。

【讨论】:

  • 感谢您提供的示例。我希望这也适用于容器,否则可能需要 DR。
  • 是的,我也希望如此——我现在正在查看第 23 节,看看它对那里的比较 arg 有什么看法。还有 ta 赞成投票,这是我在 stackoverflow 上的第一篇文章 :)
  • 23.2.4/2:“每个关联容器都在 Key 和一个排序关系 Compare 上进行参数化,从而对 Key 的元素进行严格的弱排序 (25.4)。”
  • @je4d:完美!既然你指出了它,我想知道我怎么会误读它。我想我的大脑是超前的,使用集合和地图保持排序的隐含知识——这当然与排序不同。谢谢。
  • @towi Ta 我第一次接受 :) 但请注意底部的编辑和 Dennis Zickefoose 的评论,在 §23.2.4.(2) 中暗示相同的约束适用于 Comparator 类型已排序的容器,因此我认为这是 libstdc++v3 中的一个错误。
【解决方案2】:

我是否正确理解了对于 set 显式 bool 转换也应该有效的标准?

这是规范的灰色地带。比较函数的返回值需要“可转换为布尔值”。但是对于explicit operator bool(),这意味着什么还不清楚。

例如,可以这样写std::set的比较用法:

CompFunc functor;
if(functor(input, currVal))
  ...

或者,可以这样做:

CompFunc functor;
bool test = functor(input, currVal);
if(test)
  ...

在 C++11 下,这两种技术在技术上是否合法?不知道。如果operator bool()explicit,显然第二个失败。

我查看了std::shared_ptr 的定义,它也有一个explicit operator bool()。它还在第 20.7.2.2 节第 2 段中说 std::shared_ptr 是“可转换为布尔值”。

所以我猜测第二个版本应该实现如下:

CompFunc functor;
bool test = static_cast<bool>(functor(input, currVal));
if(test)
  ...

规范中没有明确说明的事实意味着它应该作为缺陷报告提交。但它可能也应该作为 GCC/libstdc++ 错误提交。

就个人而言,为了安全起见,我不会依赖它。


关于上下文转换

第 4 节第 3 段规定:

出现在这种上下文中的表达式 e 被认为是上下文转换为 bool 的,并且当且仅当声明 bool t(e);是良构的,对于一些发明的临时变量 t

所以“上下文可转换为布尔值”的操作意味着explicit operator bool() 可以工作。由于std::set 的“Compare”函子必须符合 25.4 的要求,并且这些要求包括“contextually convert to bool”,所以它看起来像一个 GCC/libstdc++ 错误。

不过,如果你能帮上忙,我还是会避免这样做。

【讨论】:

  • 引用的关键部分“当上下文转换为 bool (4)”。我认为标准中的 contextually 专门用于抵消explicit 转换为bool
  • @MatthieuM.:见我的附录。
  • 你认为“std::shared_ptr is convertible to bool”是指“上下文转换”吗?或者shared_ptr&lt;X&gt; x ... ; bool b = (bool)x; 也符合“可转换为布尔”的条件?
猜你喜欢
  • 2014-09-07
  • 1970-01-01
  • 1970-01-01
  • 2018-01-03
  • 2014-09-07
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多