Инициализация скобок предотвращает неконстантное использование временных

Я хочу создать временную копию объекта const и использовать его неконстантным способом:

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

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

Используя msvc (Visual Studio 2017, С++ 14), я получаю эту ошибку:

Ошибка C2662 & S:: f (void) ': не может преобразовать указатель 'this' из' const S 'в &'

Если я изменил инициализацию скобки на классическую инициализацию, она работает:

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

Оба варианта компилируются в gcc. Я что-то упустил или это ошибка компилятора?

Ответ 1

Похоже на ошибку компилятора или на результат странной оптимизации, поскольку этот вариант исходного кода, который делает только ctors и dtor с побочными эффектами, компилируется с использованием 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;
}

Компиляция выполнена успешно, а вывод:

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

Ответ 2

Похоже на другую ошибку MSVC.

S{a} выводится как const struct S, и это само по себе является ошибкой.

#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;
}

Вывод:

const struct S