Опытным путем определить значение категории выражения C++11?
Каждое выражение в C++11 имеет категорию значений. Один из lvalue, xvalue или prvalue.
Есть ли способ написать макрос, который, учитывая любое выражение в качестве аргумента, будет выдавать строку "lvalue", "xvalue" или "prvalue" в зависимости от ситуации?
Например:
int main()
{
int x;
cout << VALUE_CAT(x) << endl; // prints lvalue
cout << VALUE_CAT(move(x)) << endl; // prints xvalue
cout << VALUE_CAT(42) << endl; // prints prvalue
}
Как мог VALUE_CAT
быть реализованным?
3 ответа
decltype
может возвращать объявленный тип объекта (отсюда и имя), но также может использоваться для запроса типа выражения. Однако в последнем случае результирующий тип "корректируется" в соответствии с категорией значений этого выражения: выражение lvalue приводит к ссылочному типу lvalue, xvalue для ссылочного типа rvalue и prvalue только для типа. Мы можем использовать это в наших интересах:
template<typename T>
struct value_category {
// Or can be an integral or enum value
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";
};
// Double parens for ensuring we inspect an expression,
// not an entity
#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value
Вы также можете попробовать использовать Clang API Classification
функция для возврата категории выражения из лягушки AST, содержащей выражение. Это, конечно, намного сложнее, чем решение @Luc, так как для этого требуется генерировать реальный AST через clang.
#ifndef _TPF_TYPE_NAME_H
#define _TPF_TYPE_NAME_H
template <typename T>
constexpr bool is_lvalue_helper = std::is_lvalue_reference<T>::value;
template <typename T>
constexpr bool is_xvalue_helper = std::is_rvalue_reference<T>::value;
template <typename T>
constexpr bool is_prvalue_helper = !(is_lvalue_helper<T> || is_xvalue_helper<T>);
template <typename T>
constexpr bool is_rvalue_helper = is_xvalue_helper<T> || is_prvalue_helper<T>;
template <typename T>
constexpr bool is_glvalue_helper = is_xvalue_helper<T> || is_lvalue_helper<T>;
#define is_lvalue(type_instance) is_lvalue_helper<decltype((type_instance))>
#define is_xvalue(type_instance) is_xvalue_helper<decltype((type_instance))>
#define is_prvalue(type_instance)is_prvalue_helper<decltype((type_instance))>
#define is_rvalue(type_instance) is_rvalue_helper<decltype((type_instance))>
#define is_glvalue(type_instance)is_glvalue_helper<decltype((type_instance))>
#endif // end of _TPF_TYPE_NAME_H