Search code examples
c++lambdatype-deduction

Can I capture an object as a const when using init caputre?


When using C++14's init capture, 'auto' type deduction rules are applied (which throws away the reference, const and volatile)

Notice here that I'm not saying const reference. If I wanted a const reference I can write:

auto lambda = [&widget = std::as_const(widget)] () {};
// C++17

Or I can add & to lhs cast the rhs as a const reference.

what I'm asking for is: can I write something like this?:

auto lambda = [const widget = widget] () {};

Solution

  • There is no way to capture an object by value and have it be const. The grammar for an init-capture is

    init-capture:
        identifier initializer
        & identifier initializer
    

    where identifier is

    identifier:
        identifier-nondigit
        identifier identifier-nondigit
        identifier digit
    

    Which means you can only specify a name, without any cv-qualifers. For a non mutable lambda this isn't an issue since the function will be const and you can't modify a capture by value object.

    For a mutable lambda you can capture a reference to const like you do with [&widget = std::as_const(widget)]. If you can't or don't want to have a reference then you need a write a const wrapper like

    template <typename T>
    class const_wrapper
    {
        const T obj;
    public:
        const_wrapper(T obj) : obj(obj) {}
        operator const T&() const { return obj; }
    };
    

    The above object is copyable, but not assignable (because of the const member) and only allows const access to the underlying type.