Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在另一个lambda中捕获lambda可能违反常量限定符_C++_Lambda - Fatal编程技术网

C++ 在另一个lambda中捕获lambda可能违反常量限定符

C++ 在另一个lambda中捕获lambda可能违反常量限定符,c++,lambda,C++,Lambda,考虑以下代码: int x = 3; auto f1 = [x]() mutable { return x++; }; auto f2 = [f1]() { return f1(); }; 这将不会编译,因为f1()不是常量,f2未声明为可变。这是否意味着如果我有一个库函数,它接受任意函数参数并在lambda中捕获它,我总是需要使lambda可变,因为我不知道用户可以传入什么?值得注意的是,在std::function中包装f1似乎可以解决这个问题(如何解决?) 这是否意味着如

考虑以下代码:

int x = 3;
auto f1 = [x]() mutable
{
    return x++;
};
auto f2 = [f1]()
{
    return f1();
};
这将不会编译,因为
f1()
不是常量,
f2
未声明为可变。这是否意味着如果我有一个库函数,它接受任意函数参数并在lambda中捕获它,我总是需要使lambda可变,因为我不知道用户可以传入什么?值得注意的是,在
std::function
中包装
f1
似乎可以解决这个问题(如何解决?)

这是否意味着如果我有一个库函数,它接受任意函数参数并在lambda中捕获它,我总是需要使lambda可变,因为我不知道用户可以传入什么

这是库API的设计决策。您可以要求客户机代码使用
常量
限定的
运算符()
传递函数对象(对于非
可变的
lambda表达式就是这种情况)。如果传递了不同的内容,则会触发编译器错误。但是如果上下文可能需要修改其状态的函数对象参数,那么是的,您必须使内部lambda
可变

另一种方法是调度调用给定函数类型的
const
限定实例上的
操作符()
的能力。沿着这些思路(请注意,这需要修复同时具有
const
和非
const
操作符()
的函数对象,这会导致歧义):


这是一个已知的问题,值得检查一下。

我将首先解决您的第二个问题
std::function
type擦除并保存初始化时使用的函子的副本。这意味着在
std::function::operator()
和实际functor的
operator()之间有一层间接关系

想象一下,如果你愿意的话,用指针在你的类中保存一些东西。然后,您可以从类的const member函数对指针对象调用一个变异操作,因为它不会影响(在浅视图中)类所持有的指针。这与您观察到的情况类似

至于你的第一个问题。。。“总是”这个词太重了。这取决于你的目标

  • 如果您想轻松地支持自变异函子,那么应该捕获可变lambda。但请注意,它可能会影响您现在调用的库函数

  • 如果您希望支持非变异操作,那么可以使用不可变的lambda。我之所以说“青睐”,是因为正如我们所观察到的,类型系统可以通过额外的间接层次被“愚弄”。因此,您喜欢的方法只是更易于使用,而不是无法使用。这就是sage的建议,让正确使用API变得容易,而不正确的API则更难


  • 顺便说一句,Rust的大多数函数都是这样的(即使在
    fold
    的情况下,大多数时候它可能会被
    Fn
    调用),可能是@rustyx的重复,谢谢,这回答了最后一点,但不是整个问题。“lambda违反const限定符”听起来像科幻电影中的东西。值得注意的是,在
    std::ref
    中包装一个传递的lambda提供了一种间接级别,即使在
    const
    上下文中也允许可变。如果您在跟踪某个状态之后,它还绕过了“可能会在实现中复制函子”。
    template <class Fct>
    auto wrap(Fct&& f) -> decltype(f(), void())
    {
       [fct = std::forward<Fct>(f)]() mutable { fct(); }();
    }
    
    template <class Fct>
    auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
    {
       [fct = std::forward<Fct>(f)]() { fct(); }();
    }
    
    const std::function<void()> f = [i = 0]() mutable { ++i; };
    
    f(); // Shouldn't be possible, but unfortunately, it is