struct STest : public boost::noncopyable {
STest(STest && test) : m_n( std::move(test.m_n) ) {}
explicit STest(int n) : m_n(n) {}
int m_n;
};
STest FuncUsingConst(int n) {
STest const a(n);
return a;
}
STest FuncWithoutConst(int n) {
STest a(n);
return a;
}
void Caller() {
// 1. compiles just fine and uses move ctor
STest s1( FuncWithoutConst(17) );
// 2. does not compile (cannot use move ctor, tries to use copy ctor)
STest s2( FuncUsingConst(17) );
}
Приведенный выше пример иллюстрирует, как в С++ 11, реализованном в Microsoft Visual С++ 2012, внутренние детали функции могут изменять свой тип возврата. До сегодняшнего дня я понимал, что декларация типа возврата - все, что программист должен знать, чтобы понять, как будет обрабатываться возвращаемое значение, например, при передаче в качестве параметра для последующего вызова функции. Не так.
Мне нравится делать локальные переменные const
, где это необходимо. Это помогает мне очистить мой ход мысли и четко структурировать алгоритм. Но остерегайтесь возврата переменной, объявленной const
! Даже несмотря на то, что переменная больше не будет доступна (в конце была выполнена инструкция return
), и даже несмотря на то, что переменная, которая была объявлена const
, уже давно вышла за рамки (оценка выражения параметра завершена), она не может быть перемещен и, следовательно, будет скопирован (или не скомпилирован, если копирование невозможно).
Этот вопрос связан с другим вопросом, Переместить семантику и вернуть значения const. Разница в том, что в последнем объявлена функция, возвращающая значение const
. В моем примере объявлено, что FuncUsingConst
возвращает изменчивое временное значение. Тем не менее, результирующие детали тела функции влияют на тип возвращаемого значения и определяют, можно ли использовать возвращаемое значение в качестве параметра для других функций.
Является ли это поведение стандартным?
Как это можно считать полезным?
Бонусный вопрос: как компилятор может узнать разницу во время компиляции, учитывая, что вызов и реализация могут быть в разных единицах перевода?
EDIT: попытка перефразировать вопрос.
Как возможно, что результат функции больше, чем объявленный тип возврата? Как вообще кажется приемлемым, что объявление функции недостаточно для определения поведения возвращаемого значения функции? Для меня это похоже на FUBAR, и я просто не уверен, виноват ли стандарт или реализация Microsoft.
Как разработчик вызываемой функции, я не ожидаю, что даже узнаю всех абонентов, не говоря уже о том, чтобы отслеживать каждое небольшое изменение в вызывающем коде. С другой стороны, как исполнитель вызывающей функции, я не могу полагаться на вызываемую функцию, чтобы не возвращать переменную, которая, как считается, объявлена const в рамках реализации функции.
Объявление функции - это контракт. Что это стоит? Мы не говорим о семантически эквивалентной оптимизации компилятора здесь, как copy elision, что приятно иметь, но не меняет смысл кода. Независимо от того, вызвана ли копия ctor, изменяется ли смысл кода (и может даже сломать код до такой степени, что он не может быть скомпилирован, как показано выше). Чтобы оценить неловкость того, что я здесь обсуждаю, рассмотрите "бонусный вопрос" выше.