Brace initialization prevents non-const use of temporary
Asked Answered
P

2

12

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?

Pasqualepasqueflower answered 31/3, 2017 at 11:13 Comment(4)
Which version of C++ are you using to compile your code? Assuming C++11Sinecure
fyi g++ 5.1.0 compiles okBevbevan
That's MSVC for you:Heterogamete
@Elyasin I am compiling this as C++14Pasqualepasqueflower
R
2

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
Radcliff answered 31/3, 2017 at 12:29 Comment(0)
H
3

Seems like another MSVC bug.

S{a} is deduced as const struct S, and that alone is bug.

#include <string>
#include <iostream>

template < class T >
std::string type_name()
{
    std::string p = __FUNCSIG__;
    return p.substr( 106, p.length() - 106 - 7 );
}


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

int main() {
    const S a{};
    //S{a}.f(); // Error on this line
    std::cout << type_name<decltype(S{a})>() << std::endl;
    return 0;
}

Output:

const struct S
Heterogamete answered 31/3, 2017 at 12:38 Comment(2)
I would be thankful if you could provide the link or the why that is a bug.Sinecure
@Elyasin It is a bug because there should be no type deduction at all. Direct list initialization does not deduce types.Parliament
R
2

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
Radcliff answered 31/3, 2017 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.