C++03. Test for rvalue-vs-lvalue at compile-time, not just at runtime

拟墨画扇 提交于 2019-11-28 06:51:39

It took some effort, but here's a tested and working is_lvalue macro that correctly handles const struct S function return types. It relies on const struct S rvalues not binding to const volatile struct S&, while const struct S lvalues do.

#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>();
}

Edit: unnecessary extra parameter removed, thanks Xeo.

Edit again: As per the comments, this works with GCC but relies on unspecified behaviour in C++03 (it's valid C++11) and fails some other compilers. Extra parameter restored, which makes it work in more cases. const class rvalues give a hard error on some compilers, and give the correct result (false) on others.

The address-of operator (&) can only be used with an lvalue. So if you used it in an SFINAE test, you could distinguish at compile-time.

A static assertion could look like:

#define STATIC_ASSERT_IS_LVALUE(x) ( (sizeof &(x)), (x) )

A trait version might be:

template<typename T>
struct has_lvalue_subscript
{
    typedef char yes[1];
    typedef char no[2];

    yes fn( char (*)[sizeof (&(((T*)0)->operator[](0))] );
    no fn(...);
    enum { value = sizeof(fn(0)) == 1 };
};

and could be used like

has_lvalue_subscript< std::vector<int> >::value

(Warning: not tested)

I can't think of any way to test an arbitrary expression valid in the caller's context, without breaking compilation on failure.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!