В C++03 Foreach Boost, используя этот интересный метод, может обнаруживать во время выполнения независимо от того, является ли выражение lvalue или rvalue. (Я обнаружил это с помощью этого вопроса StackOverflow: Rvalues в C++03)
Вот демонстрация работы во время выполнения
(Это более простой вопрос, который возник, когда я думал об этом другой мой недавний вопрос. Ответ на этот вопрос может помочь нам ответить на другой вопрос.)
Теперь, когда я изложил вопрос, проверяя rvalue-ness в C++03 во время компиляции, я немного расскажу о том, что я пробовал до сих пор.
Я хочу иметь возможность выполнять эту проверку во время во время компиляции. Это просто в С++ 11, но мне интересно узнать о С++ 03.
Я пытаюсь развить их идею, но также открыт для различных подходов. Основная идея их метода заключается в том, чтобы поместить этот код в макрос:
true ? rvalue_probe() : EXPRESSION;
Это «истина» слева от ?
, и поэтому мы можем быть уверены, что EXPRESSION никогда не будет оцениваться. Но интересно то, что оператор ?:
ведет себя по-разному в зависимости от того, являются ли его параметры значениями lvalue или rvalue (щелкните ссылку выше, чтобы узнать подробности). В частности, он преобразует наш объект 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"; }
};
Это работает во время выполнения, потому что сброшенный текст можно перехватить и использовать для анализа того, было ли ВЫРАЖЕНИЕ lvalue или rvalue. Но я хочу каким-то образом определить во время компиляции, какое преобразование используется.
Теперь это потенциально полезно, потому что это означает, что вместо того, чтобы спрашивать
Является ли EXPRESSION rvalue?
мы можем спросить:
Когда компилятор компилирует true ? rvalue_probe() : ВЫРАЖЕНИЕ, какой из двух перегруженных операторов,
operator X
илиoperator X&
, выбран?
(Обычно вы могли бы определить, какой метод был вызван, изменив типы возвращаемых значений и получив sizeof
его. Но мы не можем сделать это с этими операторами преобразования, особенно когда они скрыты внутри ?:
.)
Я думал, что смогу использовать что-то вроде
is_reference< typeof (true ? rvalue_probe() : EXPRESSION) > :: type
Если EXPRESSION является lvalue, то выбирается operator&
, и я надеялся, что тогда все выражение будет иметь тип &
. Но, похоже, это не работает. Типы ref и не-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-versus-rvalue во время выполнения. .)
fooref
, а неfoo
. Но в любом случае, typeof по-прежнему считает, чтоtrue ?: fooref() : fooref()
не является ссылкой. - person Aaron McDaid   schedule 31.01.2012typeof(x)
иtypeof(xr)
, и они дают один и тот же тип, для меня это не имеет смысла. Вtypeof
есть несоответствия. Я получаю правильное поведение сtypeof(int&)
, но это не то же самое сtypeof(xr)
. - person Aaron McDaid   schedule 31.01.2012x
иxr
одинаковы, поэтому я предполагаю, что результатtypeof
одинаков. Существует немного другое поведение сdecltype
, которое может вам помочь, но ваша версия g++ не поддерживает его. - person   schedule 31.01.2012?:
, который может их различать. Я просто хочу иметь возможность сделать этот дополнительный шаг и обнаружить это во время выполнения. - person Aaron McDaid   schedule 01.02.2012&
, обрабатывается как lvalue - (постоянная или неконстантная, ссылка или не ссылка, возврат из -функция против именованной локальной переменной) - person Aaron McDaid   schedule 01.02.2012x
- это lvalue, оно обрабатывается как rvalue, и ваш комментарий утверждает, что поведение дляx
является правильным. Почему же тогда это правильно? - person   schedule 01.02.2012xr
как выражение является выражением lvalue, которое имеет типX
.x
как выражение также является выражением lvalue типаX
. - person   schedule 01.02.2012char (&helper(...))[1];
/template <typename T> char (&helper(T&))[2];
/#define is_lvalue(x) (sizeof(helper(x)) == 2)
? - person   schedule 01.02.2012operator X
илиoperator X&
в качестве преобразователя. Это то, что я пытаюсь использовать во время компиляции. - person Aaron McDaid   schedule 01.02.2012operator X
илиoperator X&
) был выбран?. Я обновлю свой вопрос. - person Aaron McDaid   schedule 01.02.2012is_lvalue(true ? rvalue_probe() : x)
, что даст вам тот же результат, что иis_lvalue(x)
. Я вполне могу что-то упустить, но было бы полезно, если бы вы могли уточнить, что это за что-то. - person   schedule 01.02.2012const
lvalues.const
lvalue выглядит очень похоже на rvalue. Я поиграю с этимhelper
, о котором вы упомянули. - person Aaron McDaid   schedule 01.02.2012const X fooc();
является lvalue. Но довольно странно иметь const в таком возвращаемом значении, так что это не проблема. Но если все так просто, то почему FOREACH Boost доставил столько хлопот? :-) Может быть, я упускаю что-то более очевидное :-) - person Aaron McDaid   schedule 01.02.2012const X
является допустимым аргументом для параметра функцииconst X &
, и это используемая перегрузка. Подожди... - person   schedule 01.02.2012T&
с аргументом rvalue типа int, выведенным вT = int
, что делает его ошибкой. Я подозреваю, что вы лучше меня знаете, правильно ли это. - person   schedule 01.02.2012T&
, переданное rvalue типаX
, выведетX const&
. Это не так, поэтому мои предыдущие комментарии не применимы. :) - person Xeo   schedule 01.02.2012