29

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实施?

4

3 回答 3

50

decltype可以返回实体的声明类型(因此得名),但也可以用于查询表达式的类型。但是,在后一种情况下,结果类型会根据该表达式的值类别进行“调整”:左值表达式导致左值引用类型,右值引用类型中的 xvalue,以及类型中的纯右值。我们可以利用这一点:

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
于 2013-05-19T18:33:11.807 回答
1

您还可以尝试使用 clang API 的Classification函数从包含表达式的 clang AST 返回表达式的类别。当然,这比@Luc 的解决方案复杂得多,因为它需要通过 clang 生成实际的 AST。

于 2013-05-19T20:13:17.737 回答
0
#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
于 2022-02-12T14:33:33.927 回答