这里是一个演示在运行时工作的例子
(这是一个更基本的问题,当我思考我的另一个最近的问题时出现了。这个问题的答案可能会帮助我们回答那个其他的问题。)
既然我已经阐述了问题,在C++03中测试rvalue-ness是否为编译时,我将谈论一下我迄今为止尝试过的事情。
我想能够在编译时进行此检查。在C++11中很容易,但我对C++03很好奇。
我正在尝试借鉴他们的想法,但也愿意接受不同的方法。他们的技术的基本思路是将这段代码放入宏中:
true ? rvalue_probe() : EXPRESSION;
在?
的左侧是"true",因此我们可以确定EXPRESSION永远不会被评估。但有趣的是,?:
运算符的行为取决于其参数是lvalue还是rvalue(点击上面的链接获取详细信息)。特别地,根据EXPRESSION是否是lvalue,它将以两种方式之一转换我们的rvalue_probe
对象:
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"; }
};
那么在运行时这是可行的,因为抛出的文本可以被捕获并用于分析表达式是左值还是右值。但我希望找到一种方法来在编译时识别正在使用哪种转换方式。
现在,这有潜在的用途,因为它意味着我们可以问:
当编译器编译true ? rvalue_probe() : EXPRESSION时,两个重载运算符中的哪一个
operator X
或operator X&
被选中?
(通常情况下,您可以通过更改返回类型并获取其sizeof
来检测调用了哪个方法。但是我们无法使用这些转换运算符,特别是当它们被嵌套在?:
中时。)
我想我可以使用类似以下内容的东西:
is_reference< typeof (true ? rvalue_probe() : EXPRESSION) > :: type
如果表达式是lvalue,则选择
operator&
,我希望整个表达式都是&
类型。但似乎并不起作用。引用类型和非引用类型很难(或者说不可能)区分,尤其是现在我正在尝试挖掘?:
表达式以查看选择了哪种转换。以下是演示代码:#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 - (const vs. non-const, reference vs. non-reference, return-from-function vs named local variable)。 - Aaron McDaidx
是一个左值,但它被视为右值,而你的评论声称x
的行为是正确的。那么为什么是正确的呢? - user743382char (&helper(...))[1];
/template <typename T> char (&helper(T&))[2];
/#define is_lvalue(x) (sizeof(helper(x)) == 2)
这种常规技巧不起作用吗? - user743382