【问题标题】:Empirically determine value category of C++11 expression?凭经验确定 C++11 表达式的值类别?
【发布时间】:2013-05-19 18:19:08
【问题描述】:

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 怎么实现?

【问题讨论】:

  • 类似于#define VALUE_CAT(expr) get_value_description(sizeof SFINAE_test_1((expr)), sizeof SFINAE_test_2((expr)))
  • 我想出了这个,但它不认为第二个是glvalue...ideone.com/ARlW3v
  • @BenVoigt 我不认为基于重载解决方案的解决方案可以工作,因为重载集无法区分 xvalue 和 prvalue。这太糟糕了,因为可能完全避免使用宏(例如,constexpr 函数的重载集)。 (实际上我很高兴事实并非如此,这会使重载解析比现在更加复杂!)

标签: c++ c++11


【解决方案1】:

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

【讨论】:

  • 我没有意识到decltype“映射”表达式值类别(左值,xvalue,prvalue)到引用类型(左值引用到T,右值引用到T,T)。谢谢。
  • @user1131467:你必须使用 decltype 和这样用双括号括起来的表达式。这改变了decltype 推断表达式类型的方式。
  • decltype(...) 记录在 N3485 7.1.6.2/4
  • @NicolBolas:仅当它是 id-expression 时。例如decltype(move(x)) 将按预期生成int&amp;&amp;
【解决方案2】:

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

【讨论】:

    【解决方案3】:
    #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
    

    【讨论】:

      猜你喜欢
      • 2012-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多