6

Is there a way to define a function which handle only xvalue or prvalue (or is here a exclusive or) ?

For instance suppose I have a method f(foo&& f), how can I declare f to bind xvalue type and reject prvalue type and vice versa ?

struct Foo{};
void xvalue(/*what put here ?*/){}
void prvalue(/*what put here ?*/){}

void main()
{
  Foo foo;

  prvalue(Foo());//compile
  prvalue(std::move(foo)));//fail at compilation

  xvalue(std::move(foo)); //compile
  xvalue(Foo());//fail at compilation
}

Maybe by using std::enable_if and the fact that decltype(e) is a rvalue reference type for xvalues and non-reference type for prvalue ?

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
Guillaume Paris
  • 10,303
  • 14
  • 70
  • 145
  • Isn't that what's it already supposed to do? What calls to your `f` are currently compiling without a problem that you want to reject? –  Dec 27 '13 at 10:42
  • @hvd:according to my knowledge, `f(foo&& f)` can accept xvalue and prvalue, but not only accept xvalue and reject prvalue and vice versa.My question maybe clumsly asked, is percisely that. – Guillaume Paris Dec 27 '13 at 10:46
  • `f(foo&& f)` only binds to xvalues or prvalues, so based on the wording in your question, it seemed to be exactly what you wanted. Your edited comment clarifies a great deal. –  Dec 27 '13 at 10:47
  • @hvd: I have edited my question to clarified what I asked for – Guillaume Paris Dec 27 '13 at 10:50
  • Your edited question looks clear to me, I wouldn't misunderstand it like this. Interesting question. :) –  Dec 27 '13 at 10:52
  • I'm chuckling because it is exactly this question, except asked with lvalues and rvalues, that led to the invention of xvalues. Good luck on your journey! :-) – Howard Hinnant Dec 27 '13 at 16:05
  • 2
    +1 for neat question, but I am curious: what is the practical use case for this? – Yakk - Adam Nevraumont Dec 30 '13 at 20:38

1 Answers1

2

Using the code from this answer it should be trivial.

#include <type_traits>
#include <iostream>
#include <utility>

template <typename T>
bool is_xvalue()
{
    if (std::is_lvalue_reference<T>::value)
        return false;
    else if (std::is_rvalue_reference<T>::value)
        return true;
    return false;
}

template <typename T>
bool is_prvalue()
{
    if (std::is_lvalue_reference<T>::value)
        return false;
    else if (std::is_rvalue_reference<T>::value)
        return false;
    else
        return true;
    return false;
}

struct Foo {};

int main()
{
    std::cout << std::boolalpha;
    std::cout << is_prvalue<decltype(Foo())>() << "\n"; // true
    std::cout << is_prvalue<decltype(std::move(Foo()))>() << "\n"; // false
    std::cout << is_xvalue<decltype(Foo())>() << "\n"; // false
    std::cout << is_xvalue<decltype(std::move(Foo()))>() << "\n"; // true
    return 0;
}

Unfortunately, you have to explicitly instantiate the templates, or else it doesn't work for some reason.

struct Foo {};

template <typename T, typename = typename std::enable_if<is_prvalue<T>(), void>::type>
void prvalue(T&& t)
{
}

template <typename T, typename = typename std::enable_if<is_xvalue<T>(), void>::type>
void xvalue(T&& t)
{
}

prvalue<decltype(Foo())>(Foo());
// prvalue<decltype(std::move(Foo()))>(std::move(Foo())); - compile error
xvalue<decltype(std::move(Foo()))>(std::move(Foo()));
// xvalue<decltype(Foo())>(Foo()); - compile error
Community
  • 1
  • 1
  • 1
    Deduction leads to `Foo&&` perfectly matching `T&&`, giving `T = Foo`, the same that would come out of a prvalue. – Xeo Dec 27 '13 at 16:40
  • @Xeo So is it impossible? –  Dec 27 '13 at 16:46
  • With deduction? I think yes. – Xeo Dec 27 '13 at 18:01
  • I think those functions need to be `constexpr` (or metafunctions), otherwise you shouldn't be able to use them in the non-type template argument. – dyp Dec 30 '13 at 21:07