Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if a function returns a reference in C++03?

Tags:

c++

reference

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.

like image 595
user541686 Avatar asked Nov 16 '13 21:11

user541686


1 Answers

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);
}
like image 68
dyp Avatar answered Sep 29 '22 13:09

dyp