Lambda 如何在移动预期情况下检测意外复制

Lambda 如何在移动预期情况下检测意外复制,lambda,copy,c++14,move,mutable,Lambda,Copy,C++14,Move,Mutable,当我使用lambda表达式时,有时我会移动捕获可复制和可移动的对象。在下面的示例中,对象是t,其类型是tracer。在lambda表达式中,我想将t再次移动到其他函数f()f()的参数是按值传递的,因为我希望同时支持f()的复制和移动 main()I调用f(std::move(t))的第一部分,但它不是移动的,而是复制的,因为t被捕获为常量变量。main()函数的第二部分,我将mutable添加到lambda表达式中。正如我所预料的那样 我经常忘记在lambda表达式中添加mutable。如果t

当我使用lambda表达式时,有时我会移动捕获可复制和可移动的对象。在下面的示例中,对象是
t
,其类型是
tracer
。在lambda表达式中,我想将
t
再次移动到其他函数
f()
f()
的参数是按值传递的,因为我希望同时支持
f()
的复制和移动

main()
I调用
f(std::move(t))
的第一部分,但它不是移动的,而是复制的,因为
t
被捕获为常量变量。
main()
函数的第二部分,我将
mutable
添加到lambda表达式中。正如我所预料的那样

我经常忘记在lambda表达式中添加
mutable
。如果
t
是仅移动类型,则第一种情况会导致编译错误。我很容易注意到这个问题。但是如果
t
是可复制和可移动的,我就很难注意到意外的复制。我想检查一下那个箱子

有什么好办法吗

#include <iostream>

struct tracer {
    tracer() {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << std::endl;
    }
    ~tracer() {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << std::endl;
    }
    tracer(tracer const& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
    }
    tracer(tracer&& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
    }
    tracer& operator=(tracer const& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
        return *this;
    }
    tracer& operator=(tracer&& other) {
        std::cout << __PRETTY_FUNCTION__ << ":" << this << " <- " << &other << std::endl;
        return *this;
    }
};

void f(tracer) {
}

int main() {
    {
        tracer t;
        // move assign capture
        [t = std::move(t)] { // forget write mutable
            f(std::move(t)); // I expect move but copy due to lack of mutable
        }();
    }
    std::cout << "---" << std::endl;
    {
        tracer t;
        // move assign capture
        [t = std::move(t)] () mutable {
            f(std::move(t)); // Moved as I expected
        }();
    }
}
#包括
结构跟踪器{
示踪剂(){

std::cout我想我想出了一个解决方案。我为
std::move()
编写了以下包装

然后,只有当我忘记了
mutable
时,才会收到静态断言失败消息

*1错误:由于要求“!std::is_const_v”T is const.Fallback to copy,静态断言失败


运行演示:

如果您的测试用例足够小,您可以临时删除复制构造函数,以确保您确实在移动对象。@alfC感谢您的评论。它可以工作。但我的实际代码很大,有时我真的想复制
跟踪t1;跟踪t2=t1
=delete
方法使编译e错误就发生在这样的地方。找到问题的目标部分是很麻烦的。当然,我理解,这就是为什么我说测试代码必须很小(并且不涉及任何实际副本)来测试这个问题。尽管如此,测试代码无论如何都应该很小。另一种方法是让
f
只接受r值。
f(tracer&)
,同样是在小到足以执行对
f
的此类调用的测试中。
template <typename T>
typename std::remove_reference_t<T>&&
only_move(T&& t) {
    static_assert(!std::is_const_v<std::remove_reference_t<T>>, "T is const. Fallback to copy.");
    return std::move(t);
}
int main() {
    {
        tracer t;
        // move assign capture
        [t = only_move(t)] { // got static assertion failed *1
            f(only_move(t)); // I expect move but copy due to lack of mutable
        }();
    }
    std::cout << "---" << std::endl;
    {
        tracer t;
        // move assign capture
        [t = only_move(t)] () mutable {
            f(only_move(t)); // Moved as I expected
        }();
    }
}