В C ++ 03 Boost's Foreach, используя этот интересный метод , может обнаружить во время выполнения , является ли выражение lvalue или rvalue. (Я обнаружил, что с помощью этого вопроса StackOverflow: Rvalues в C ++ 03 )
Вот демонстрация этой работы во время выполнения
(Это более простой вопрос, который возник, когда я размышлял над этим другим моим недавним вопросом . Ответ на этот вопрос может помочь нам ответить на этот другой вопрос.)
Теперь, когда я изложил вопрос, проверяя rvalue-ness в C ++ 03 во время компиляции, я немного расскажу о том, что я до сих пор пробовал.
Я хочу сделать эту проверку в время компиляции . Это легко в C ++ 11, но мне любопытно, что такое C ++ 03.
Я пытаюсь опираться на их идею, но буду открыт и для других подходов. Основная идея их техники - поместить этот код в макрос:
true ? rvalue_probe() : EXPRESSION;
Это 'true' слева от ?
, и поэтому мы можем быть уверены, что EXPRESSION никогда не будет оцениваться. Но интересно то, что оператор ?:
ведет себя по-разному, в зависимости от того, являются ли его параметры lvalues или rvalues (для получения подробной информации нажмите на ссылку выше). В частности, он преобразует наш rvalue_probe
объект одним из двух способов, в зависимости от того, является ли EXPRESSION lvalue или нет:
struct rvalue_probe
{
template< class R > operator R () { throw "rvalue"; }
template< class L > operator L & () const { throw "lvalue"; }
template< class L > operator const L & () const { throw "const lvalue"; }
};
Это работает во время выполнения, потому что брошенный текст может быть перехвачен и использован для анализа того, было ли EXPRESSION lvalue или rvalue. Но я хочу каким-то образом определить во время компиляции, какое преобразование используется.
Теперь, это потенциально полезно, потому что это означает, что вместо того, чтобы спрашивать
EXPRESSION - это значение?
мы можем спросить:
Когда компилятор компилирует true? rvalue_probe (): EXPRESSION , какой из двух перегруженных операторов, operator X
или operator X&
, выбран?
(Обычно вы можете определить, какой метод был вызван, изменив возвращаемые типы и получив его sizeof
. Но мы не можем сделать это с этими операторами преобразования, особенно когда они скрыты внутри ?:
. )
Я думал, что смогу использовать что-то вроде
is_reference< typeof (true ? rvalue_probe() : EXPRESSION) > :: type
Если EXPRESSION является lvalue, тогда выбирается operator&
, и я надеялся, что тогда все выражение будет иметь тип &
. Но это не похоже на работу. Типы ref и non-ref довольно сложно (невозможно?) различить, особенно сейчас, когда я пытаюсь найти выражение ?:
, чтобы увидеть, какое преобразование было выбрано.
Вот демонстрационный код, вставленный здесь:
#include <iostream>
using namespace std;
struct X {
X(){}
};
X x;
X & xr = x;
const X xc;
X foo() { return x; }
const X fooc() { return x; }
X & foor() { return x; }
const X & foorc() { return x; }
struct rvalue_probe
{
template< class R > operator R () { throw "rvalue"; }
// template< class R > operator R const () { throw "const rvalue"; } // doesn't work, don't know why
template< class L > operator L & () const { throw "lvalue"; }
template< class L > operator const L & () const { throw "const lvalue"; }
};
typedef int lvalue_flag[1];
typedef int rvalue_flag[2];
template <typename T> struct isref { static const int value = 0; typedef lvalue_flag type; };
template <typename T> struct isref<T&> { static const int value = 1; typedef rvalue_flag type; };
int main() {
try{ true ? rvalue_probe() : x; } catch (const char * result) { cout << result << endl; } // Y lvalue
try{ true ? rvalue_probe() : xc; } catch (const char * result) { cout << result << endl; } // Y const lvalue
try{ true ? rvalue_probe() : xr; } catch (const char * result) { cout << result << endl; } // Y lvalue
try{ true ? rvalue_probe() : foo(); } catch (const char * result) { cout << result << endl; } // Y rvalue
try{ true ? rvalue_probe() : fooc(); } catch (const char * result) { cout << result << endl; } // Y rvalue
try{ true ? rvalue_probe() : foor(); } catch (const char * result) { cout << result << endl; } // Y lvalue
try{ true ? rvalue_probe() : foorc(); } catch (const char * result) { cout << result << endl; } // Y const lvalue
}
(В конце у меня был какой-то другой код, но это просто сбивает с толку. Вы действительно не хотите видеть мои неудачные попытки ответа! Приведенный выше код демонстрирует, как он может тестировать lvalue-vs.-rvalue во время выполнения .)