How can I write a decltype expression using a function that expects a non-constant reference?

Consider:

int convert_it(std::string& x) { return 5; } void takes_int_ref(int& i) { } 

I want to write a function that exists only if convert_it can be applied, and the result is passed to takes_int_ref . That is, the body of the function:

 template <typename A> void doit(A& a) { int i = convert_it(a); takes_int_ref(i); } 

However, if I do this:

 template <typename A> auto doit(A& a) -> decltype(takes_int_ref(convert_it(a)), void()) 

it does not work because invalid initialization of non-const reference of type 'int&' from an rvalue of type 'int' .

I thought of the following solution that works:

 template <typename T> T& gimme_ref(T t) { throw std::runtime_error("No"); return t; } template <typename A> auto doit(A& a) -> decltype(takes_int_ref(gimme_ref(convert_it(a))), void()) 

However, it seems decltype , and decltype no longer reflects what the function body does. Essentially, the problem is that decltype only accepts an expression, while two statements are required in the function body.

What would be the right approach?

+5
source share
2 answers

Use std::declval :

 template <typename A> auto doit(A& a) -> decltype( takes_int_ref(std::declval< decltype(convert_it(std::declval<A&>())) &>()), void()) { .. } 

std::declval<A&>() gives you an expression of type A& . convert_it(A&) will be either valid or invalid - if it is invalid, you are not executing it. If it is valid, let's say it is of type T Then you try to call takes_int_ref with T& to make sure that it is valid. If so, you will end up in void . If this is not the case, replacement failure.

+9
source

For the record, after seeing the solution std::declval , my perception is that the hacker has changed, and I ended up with this:

 template <typename T> T& lref_of(T&&); template <typename A> auto doit(A& a) -> decltype(takes_int_ref(lref_of(convert_it(a))), void()) { .. } 

Since I start with an expression, not a type, it makes lref_of(convert_it(a)) less than std::declval<decltype(convert_it(a))&>() . Also, not defining lref_of gives a compile-time error if it is used in any code that is better than defining it, just throwing an exception at run time.

+1
source

All Articles