gpt4 book ai didi

C++03.在编译时测试 rvalue-vs-lvalue,而不仅仅是在运行时

转载 作者:IT老高 更新时间:2023-10-28 21:43:15 26 4
gpt4 key购买 nike

在 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 是左值还是右值。但我想要一些方法来在编译时识别正在使用的转换。

现在,这可能很有用,因为这意味着,而不是询问

Is EXPRESSION an rvalue?

我们可以问:

When the compiler is compiling true ? rvalue_probe() : EXPRESSION, which of the two overloaded operators, operator X or operator X&, is selected?

( 通常,您可以通过更改返回类型并获取 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 在运行时。)

最佳答案

花费了一些精力,但这里有一个经过测试且可以正常工作的 is_lvalue 宏,它可以正确处理 const struct S 函数返回类型。它依赖于 const struct S 右值不绑定(bind)到 const volatile struct S&,而 const struct S 左值可以。

#include <cassert>

template <typename T>
struct nondeducible
{
typedef T type;
};

char (& is_lvalue_helper(...))[1];

template <typename T>
char (& is_lvalue_helper(T&, typename nondeducible<const volatile T&>::type))[2];

#define is_lvalue(x) (sizeof(is_lvalue_helper((x),(x))) == 2)

struct S
{
int i;
};

template <typename T>
void test_()
{
T a = {0};
T& b = a;
T (* c)() = 0;
T& (* d)() = 0;
assert (is_lvalue(a));
assert (is_lvalue(b));
assert (!is_lvalue(c()));
assert (is_lvalue(d()));
}

template <typename T>
void test()
{
test_<T>();
test_<const T>();
test_<volatile T>();
test_<const volatile T>();
}

int main()
{
test<int>();
test<S>();
}

编辑:删除不必要的额外参数,感谢 Xeo。

再次编辑:根据评论,这适用于 GCC,但依赖于 C++03 中的未指定行为(它是有效的 C++11)并且使其他一些编译器失败。恢复了额外的参数,使其在更多情况下工作。 const 类右值在某些编译器上会给出硬错误,而在其他编译器上会给出正确的结果(假)。

关于C++03.在编译时测试 rvalue-vs-lvalue,而不仅仅是在运行时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9084671/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com