Trying to distinguish between different types of rvalues ​​- literals and non-literals

I want to have a method that can only be called with lvalues, so I did the following:

template <typename T>
MyClass& cache(T&) {}

template <typename T>
MyClass& cache(const T&&) = delete;

And that works fine - I can even pass C string literals, since they are also lvalues.

The reason I need lvalues ​​is because I cache pointers to passed objects, which means that they cannot be temporary.

The following code works:

MyClass a;
a.cache("string literal");

int temp = 6;
a.cache(temp);

And the following code (optional) does not work:

int getInt(); // fwd decl
a.cache(getInt());

But I also want to be able to pass other literals, but they all seem to rvalues ​​...

The following code does not work (but I would like):

MyClass a;
a.cache(6);

Is there a way to distinguish such literals from non-literal values?

lvalues? , - unless you write 1L, L , .

- - : a.cache(TURN_TO_LVALUE(6)); ( CONSTANTIZE(6))

+6
1

"hello"; , ( ) lvalue ( const const). "hello" , , , const, {'h', 'e', 'l', 'l', 'o', '\0'}. "hello" .

6 ; ++ 6 6, "hello" ++ "hello".

6 . , ( " ", ).

, 6, , . , .

; == < undefined.

, a.cache(6) - .

- .

unsigned long long const& operator""_lvalue(unsigned long long x) {
    thread_local unsigned long long value;
    value = x;
    return value;
}

.

lvalue value x. , 6_lvalue + 4_lvalue 8, 12, 10, lwue .

.

template<int P>
constexpr unsigned long long pow_( unsigned x, std::size_t tens ) {
  if (tens == 0) return x;
  return P*pow_<P>(x, tens-1);
}
template<int base>
constexpr unsigned long long ucalc(std::integer_sequence<char>) {
  return 0;
}
constexpr unsigned digit( char c ) {
    if (c >= '0' && c <= '9') return c-'0';
    if (c >= 'a' && c <= 'z') return c-'a'+10;
    if (c >= 'A' && c <= 'Z') return c-'A'+10;
    exit(-1);
}
template<int base, char c0, char...chars>
constexpr unsigned long long ucalc(std::integer_sequence<char, c0, chars...>) {
  return pow_<base>( digit(c0), sizeof...(chars) ) + ucalc<base>( std::integer_sequence<char, chars...>{} );
}
template <char... chars>
constexpr unsigned long long calc(std::integer_sequence<char, chars...>) {
  return ucalc<10>(std::integer_sequence<char, chars...>{});
}
template <char... chars>
constexpr unsigned long long calc(std::integer_sequence<char, '0', 'x', chars...>) {
  return ucalc<16>(std::integer_sequence<char, chars...>{});
}
template <char... chars>
constexpr unsigned long long calc(std::integer_sequence<char, '0', 'X', chars...>) {
  return ucalc<16>(std::integer_sequence<char, chars...>{});
}
template <char... chars>
constexpr unsigned long long calc(std::integer_sequence<char, '0', 'b', chars...>) {
  return ucalc<2>(std::integer_sequence<char, chars...>{});
}
template <char... chars>
constexpr unsigned long long calc(std::integer_sequence<char, '0', 'B', chars...>) {
  return ucalc<2>(std::integer_sequence<char, chars...>{});
}
template <char... chars>
constexpr unsigned long long calc(std::integer_sequence<char, '0', chars...>) {
  return ucalc<8>(std::integer_sequence<char, chars...>{});
}
template <char... chars>
constexpr unsigned long long calc() {
  return calc( std::integer_sequence<char, chars...>{} );
}
template<class T, T x>
constexpr T lvalue = x;
template <char... chars>
unsigned long long const& operator "" _lvalue() {
  return lvalue<unsigned long long, calc<chars...>()>;
}

. 0b 0x 0 // .

:

a.cache(6_lvalue);

, ++ 17 :

template<auto x>
constexpr auto lvalue = x;

++ 14

template<class T, T x>
constexpr T lvalue = x;

#define LVALUE(...) lvalue<std::decay_t<decltype(__VA_ARGS__)>, __VA_ARGS__>

++ 17 lvalue<7>, ++ 14 LVALUE(7).

+5

Source: https://habr.com/ru/post/1016909/


All Articles