Ответ 1
Visual Studio 2015 не создает правильный результат для:
F{a}
Результат должен быть prvalue (gcc и clang оба имеют этот результат), но он производит lvalue. Для получения этого результата я использую следующую измененную версию OP-кода:
#include <iostream>
class F {
public:
F(int n, int d) :n_(n), d_(d) {};
F(const F&) = default ;
F& operator *= (const F&){return *this; }
F& operator *= (int) { return *this; }
int n() const { return n_ ; }
int d() const { return d_ ; }
int n_, d_ ;
};
template<typename T>
struct value_category {
static constexpr auto value = "prvalue";
};
template<typename T>
struct value_category<T&> {
static constexpr auto value = "lvalue";
};
template<typename T>
struct value_category<T&&> {
static constexpr auto value = "xvalue";
};
#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value
int main()
{
const F a{3, 7};
const F b{5, 10};
std::cout << "\n" << VALUE_CATEGORY( F{a} ) << "\n";
}
Совет о шляпе Люк Дантон для кода VALUE_CATEGORY().
Visual Studio с использованием webcompiler, который имеет относительно новую версию:
lvalue
который должен быть const в этом случае, чтобы вызвать ошибку, которую мы видим. Хотя gcc и clang (см. Его в прямом эфире) производят:
prvalue
Это может быть связано с одинаково загадочной ошибкой Visual Studio std:: move строкового литерала - какой компилятор верен?.
Обратите внимание, что мы можем получить ту же проблему с gcc и clang, используя const F:
using cF = const F ;
auto result = cF{a} *= b;
поэтому Visual Studio не только дает нам неправильную категорию значений, но также произвольно добавляет cv-квалификатор.
Как отметил Ханс в своих комментариях к вашему вопросу, используя F(a)
, вы получите ожидаемые результаты, так как он корректно создает prvalue.
Соответствующим разделом проекта стандарта С++ является раздел 5.2.3
[expr.type.conv], в котором говорится:
Аналогично, спецификатор simple-type-specifier или typename-specifier, за которым следует список braced-init-list, создает временную объект указанного типа с прямым списком-инициализацией (8.5.4) с указанным скобками-init-list и его значение равно этот временный объект как prvalue.
Заметьте, насколько я могу судить, это не старая ошибка MSVC lvalue cast. Решение этой проблемы заключается в использовании /Zc:rvalueCast
, которая не устраняет эту проблему. Эта проблема также отличается неправильным добавлением cv-квалификатора, который, насколько я знаю, не происходит с предыдущей проблемой.