In C++03, Boost\'s Foreach, using this interesting technique, can detect at run-time whether an expression is an lvalue or an rvalue. (I found that via this StackOv
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.