Search code examples
c++temporarylist-initialization

Brace initialization prevents non-const use of temporary


I want to create a temporary copy of a const object and use it in a non-const way:

struct S {
    S& f() { return *this; }
};

int main() {
    const S a{};
    S{a}.f(); // Error on this line
    return 0;
}

Using msvc (Visual Studio 2017, C++14), I get this error:

Error C2662 'S &S::f(void)': cannot convert 'this' pointer from 'const S' to 'S &'

If I change the brace initialization to classic initialization, it works:

S{a}.f(); // Does not work
S(a).f(); // Works

Both variants compile fine in gcc. Am I missing something or is this a compiler bug?


Solution

  • It looks like a compiler bug, or the result of a weird optimization, because this variation of original code that only make ctors and dtor with side effects compiles fine using MSVC:

    #include <iostream>
    
    struct S {
        S(const S& other) {
            std::cout << "Copy ctor " << &other << " -> " << this << std::endl;
        }
        S() {
            std::cout << "Default ctor " << this << std::endl;
        }
        ~S() {
            std::cout << "Dtor " << this << std::endl;
        }
        S& f() { return *this; }
    };
    
    int main() {
        const S a{};
        std::cout << &a << std::endl;
        S{a}.f();
        return 0;
    }
    

    Compilation is successful and output is:

    Default ctor 0306FF07
    Copy ctor 0306FF07 -> 0306FF06
    Dtor 0306FF06
    Dtor 0306FF07