为什么 std::sentinel_for 概念需要默认可构造性?

Why does the std::sentinel_for concept require default constructability?

为什么新的 std::sentinel_for 概念要求哨兵类型是 default_initializable(通过 semiregular)?这是否排除了默认构造没有任何意义的大量 class 有用的哨兵类型?

示例:

//Iterate over a string until given character or '[=11=]' is found
class char_sentinel
{
public:
    char_sentinel(char end) :
        end_character(end)
    { }

   friend bool operator==(const char* lhs, char_sentinel rhs)
   {
       return (*lhs == '[=11=]') || (*lhs == rhs.end_character);
   }

   friend bool operator!=(const char* lhs, char_sentinel rhs) { ... }
   friend bool operator==(char_sentinel lhs, const char* rhs) { ... }
   friend bool operator!=(char_sentinel lhs, const char* rhs) { ... }

private:
    char end_character; 
};

我知道我可以添加一个初始化为 '[=15=]' 的默认构造函数,但是如果我认为这是对结构的滥用并希望阻止这种情况怎么办?

虽然这不是 this question 的严格重复,但我的回答在很大程度上仍然适用。

关于类型行为的编程基础设计哲学是它们应该是 regular,EoP 定义为:

T’s computational basis includes equality, assignment, destructor, default constructor, copy constructor, total ordering (or default total ordering) and underlying type

我认为随着时间的推移,这一定义已被证明不是最有用的定义。很多算法都不需要相等性,因此 semiregular。但是在许多情况下甚至不需要默认构造。

虽然我们在 P2325R3 中删除了输入迭代器、输出迭代器和视图的默认构造要求,但那篇论文没有触及(甚至讨论)哨兵。哨兵的论点在很大程度上是相同的——这不是一个重要的要求,算法也不需要它——但我们只是没有追求弱化 sentinel_for 从需要 semiregular 到只需要 copyable。我不确定我们是否有充分的理由避免这样做,除了不值得,因为哨兵的编写频率无论如何都低于迭代器。