【发布时间】:2012-02-23 11:23:50
【问题描述】:
在 C++03 中,Boost 的 Foreach 使用 this interesting technique,可以在运行时检测表达式是左值还是右值。 (我通过这个 StackOverflow 问题发现:Rvalues in C++03)
这是demo of this working at run-time
(这是我在考虑other recent question of mine 时提出的一个更基本的问题。对此的回答可能有助于我们回答其他问题。)
现在我已经说明了问题,在编译时测试 C++03 中的右值性,我将谈谈到目前为止我一直在尝试的事情。
我希望能够在编译时进行此检查。在 C++11 中很容易,但我对 C++03 很好奇。
我正在尝试以他们的想法为基础,但也愿意接受不同的方法。他们技术的基本思想是将这段代码放入一个宏中:
true ? rvalue_probe() : EXPRESSION;
? 左边是“真”,因此我们可以确定 EXPRESSION 永远不会被计算。但有趣的是,?: 运算符的行为会有所不同,具体取决于其参数是左值还是右值(单击上面的链接了解详细信息)。特别是,它将以两种方式之一转换我们的rvalue_probe 对象,具体取决于 EXPRESSION 是否为左值:
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"; }
};
这在运行时有效,因为抛出的文本可以被捕获并用于分析 EXPRESSION 是左值还是右值。但我想要一些方法来在编译时识别正在使用的转换。
现在,这可能很有用,因为这意味着,而不是询问
EXPRESSION 是右值吗?
我们可以问:
编译器何时编译 true ? rvalue_probe() : EXPRESSION,选择
operator X或operator X&这两个重载运算符中的哪一个?
( 通常,您可以通过更改返回类型并获取sizeof 来检测调用了哪个方法。但是我们不能使用这些转换运算符来做到这一点,尤其是当它们被埋在?: 中时。 )
我认为我可以使用类似的东西
is_reference< typeof (true ? rvalue_probe() : EXPRESSION) > :: type
如果 EXPRESSION 是左值,则选择 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 在运行时。)
【问题讨论】:
-
@hvd,我已经相应地更新了问题的结尾。我应该说
fooref,而不是foo。但无论如何,typeof 仍然认为true ?: fooref() : fooref()不是 引用。 -
@hvd, ...我还检查了
typeof(x)和typeof(xr),它们给出的类型相同,这对我来说没有意义。typeof中似乎存在不一致之处。我使用typeof(int&)得到了正确的行为,但使用typeof(xr)却没有做同样的事情。 -
x和xr的类型和左值是相同的,所以我假设这就是typeof的结果相同的原因。decltype的行为略有不同,可能会对您有所帮助,但您的 g++ 版本不支持它。 -
你试图发明标准的is_lvalue_reference/is_rvalue_reference?或者我错过了什么。
-
@Andrew 现在看到你的留言,我认为问题是“x 是左值”和“x 是参考”是两个不同的问题,在问题中很困惑。
标签: c++ language-lawyer rvalue c++03