views::take_while 中的参数推导失败

n. *_* m. 2 c++ c++20

我有这个代码:

for (auto e : foo | ::std::views::take_while([](const char* x) { return x != nullptr; }))
      std::cout << e << "\n";
Run Code Online (Sandbox Code Playgroud)

一切都很好,很花哨,但是这个 lambda 很长很笨拙。由于它发生了很多次,我决定用一个命名的函数对象来代替。

class non_null                                    
{ 
    template <typename T> bool operator()(const T* t) {
            return t != nullptr;
    }
};

for (auto e : foo | ::std::views::take_while(non_null()))
      std::cout << e << "\n";
Run Code Online (Sandbox Code Playgroud)

这无法通过大量错误消息进行编译,顶部有“类模板参数推导失败”。

为什么?可以做些什么呢?(除了take_while使用非模板化谓词调用,这显然有效)。

cig*_*ien 5

std::views::take_while 需要传递给它的对象的调用运算符是 const 限定的,以便推导成功:

struct non_null                                    
{ 
    template <typename T> 
    bool operator()(const T* t) const {  // <-- const-qualified
            return t != nullptr;
    }
};
Run Code Online (Sandbox Code Playgroud)

但是,如果您只想命名谓词,您可以简单地执行以下操作:

auto non_null = [](const auto* x) { return x != nullptr; };
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

for (auto e : foo | ::std::views::take_while(non_null))
      std::cout << e << "\n";
Run Code Online (Sandbox Code Playgroud)

这是一个演示

  • [标准的相关部分](http://eel.is/c++draft/range.take.while#sentinel-3)。由“end”返回的“take_while_range&lt;V, non_null&gt;::sentinel”最终通过“non_null const*”(所有仅用于展示,ofc)引用“non_null”,以及“operator==”之间的“operator==”。因此,迭代器和结束哨兵需要“non_null::operator()”来将“*this”作为“const”。 (2认同)