Опытным путем определить значение категории выражения 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
Другие вопросы по тегам