C++ Logo

std-discussion

Advanced search

C++20 unexpectedly calling const overload of constructor

From: Rob Lefebvre <rob_lefebvre_at_[hidden]>
Date: Wed, 11 Mar 2020 18:11:09 +0000
I have a situation where the new overload rules of C++ 20/move semantics is breaking existing code that does not use move or rvalue constructors. I had previously posted this to https://stackoverflow.com/questions/59938540/const-overload-unexpectedly-called-in-gcc-compiler-bug-or-compatibility-fix. where the consensus is that this is a language change for C++20 (although, it is now implemented in the latest gcc and Visual Studio even when the standard is set to C++17).

The problem is in this code (the version on stack overflow uses a template, but that is not needed to demonstrate the issue):

#include <iostream>

class MyClass
{
public:
    MyClass(const char (&value)[30])
    {
        std::cout << "CONST " << value << '\n';
    }

    MyClass(char (&value)[30])
    {
        std::cout << "NON-CONST " << value << '\n';
    }
};

MyClass test_1()
{
    char buf[30] = "test_1";
    return buf;
}

int main()
{
    auto result = test_1();
}

https://godbolt.org/z/PdYA94

It will output "CONST test_1". Before recent language changes (described on the stack overflow page), it would have output "NON-CONST test_1".

This simply doesn't seem right. I have a non-const object that I'm passing into the constructor, and it seems that I should get the non-const behavior. One of the guiding principles of rvalue references is that if you don't use it, it doesn't mess with existing code. If this is in fact what the upcoming c++20 standard specifies, that sounds like a standard bug.

Another way to look at this: If I eliminate the const overload, then the non-const version is called. If the addition of a const overload causes non-const objects to start calling the const overload, that is just intuitively wrong -- essentially a bug in the overload rules.

The way to "solve" this in code example above is to add an rvalue reference overload:

    MyClass(char (&&value)[30])
    {
        std::cout << "RVALUE " << value << '\n';
    }
https://godbolt.org/z/s_b5u4

After that change, it will output "RVALUE test_1".

I'm not versed enough in the language specification to be able to propose a solution to this issue.

Thank you for your consideration.

Rob Lefebvre
Keysight Technologies

Received on 2020-03-11 13:13:58