In pre-C++11, how can I determine if a given function returns a reference or not, when called with particular arguments?
For example, if the code looks like this:
template<class F>
bool returns_reference(F f) { return is_reference(f(5)); }
then how should I implement is_reference
?
Note that f
may also be a functor, and its operator()
may have multiple overloads -- I only care about the overload that actually gets called via my arguments here.
Here's a SFINAE-based solution that checks if a function-call expression yields an lvalue:
#include <boost/type_traits.hpp>
#include <boost/utility.hpp>
#include <cstddef>
// Func: function (object/pointer/reference) type
// Arg0: type of the first argument to use (for overload resolution)
template<class Func, class Arg0>
struct yields_lvalue_1 // with one argument
{
typedef char yes[1];
typedef char no[2];
// decay possible function types
typedef typename boost::decay<Func>::type F_decayed;
// a type whose constructor can take any lvalue expression
struct Any
{
template<class T>
Any(T&);
};
// SFINAE-test: if `Any(....)` is well-formed, this overload of `test` is
// viable
template<class T>
static yes& test(boost::integral_constant<std::size_t,
sizeof(Any( boost::declval<T>()(boost::declval<Arg0>()) ))>*);
// fall-back
template<class T>
static no& test(...);
// perform test
static bool const result = sizeof(test<F_decayed>(0)) == sizeof(yes);
};
Some exemplary function objects:
struct foo
{
bool& operator()(int);
bool operator()(double);
};
struct bar
{
template<class T>
double operator()(T);
};
Usage example:
#include <iostream>
#include <iomanip>
void print(bool expect, bool result)
{
std::cout << "expect: "<<std::setw(5)<<expect<<" -- result: "<<result<<"\n";
}
int main()
{
std::cout << std::boolalpha;
print(true , yields_lvalue_1<foo, int> ::result);
print(false, yields_lvalue_1<foo, double>::result);
print(false, yields_lvalue_1<bar, int> ::result);
print(true , yields_lvalue_1<foo&(*)(long), int>::result);
print(false, yields_lvalue_1<void(*)(int), short>::result);
print(true , yields_lvalue_1<bool&(short), long>::result);
print(false, yields_lvalue_1<void(float), int>::result);
print(true , yields_lvalue_1<char&(&)(bool), long>::result);
print(false, yields_lvalue_1<foo(&)(int), short>::result);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With