在 C++03 中,Boost 的 Foreach 使用这种有趣的技术,可以在运行时检测表达式是左值还是右值。(我通过这个 StackOverflow 问题发现:Rvalues in C++03)
(这是我在考虑我最近提出的另一个问题时出现的一个更基本的问题。对此的答案可能有助于我们回答另一个问题。)
现在我已经说明了问题,在编译时测试 C++03 中的右值性,我将谈谈我迄今为止一直在尝试的事情。
我希望能够在compile-time进行此检查。在 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
}
(最后我在这里有一些其他代码,但这只是令人困惑的事情。你真的不想看到我在答案中失败的尝试!上面的代码演示了它如何在运行时测试左值与右值。)