8

It works just fine, for plain vanilla functions. The code below works just fine. It prints just what is should:

int __cdecl(int, char)
2
int,char

#include <boost/type_traits.hpp>
#include <boost/function.hpp>
#include <boost/typeof/std/utility.hpp>

#include <iostream>

using std::cout;
using std::endl;

int foo(int, char) {
 return 0;
}
int main() {
    typedef BOOST_TYPEOF(foo) foo_type;;
    typedef boost::function_traits<foo_type> function_traits;

    cout << typeid(foo_type).name() << endl;
    cout << function_traits::arity << endl;
    cout << typeid(function_traits::arg1_type).name() << ",";
    cout << typeid(function_traits::arg2_type).name() << endl;

    return 0;
}

So, the question is, how can one do this if foo is a member function of class bar?

struct bar {
    int foo(int, char) { return 0; }
};

I have tried countless combinations of these constructs: BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() BOOST_TYPEOF_REGISTER_TYPE() boost::ref boost::remove_pointer boost::bind boost::mem_fn

etc., etc... No joy.

Jive Dadson
  • 16,680
  • 9
  • 52
  • 65

3 Answers3

10

Boost Function Types would probably be the natural solution:

#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/typeof/std/utility.hpp>
#include <boost/typeof/typeof.hpp>
#include <iostream>

struct bar {
    int foo(int, char) { return 0; }
};

int main() {

    typedef BOOST_TYPEOF(&bar::foo) foo_type;

    std::cout << typeid(foo_type).name() << std::endl;
    std::cout << boost::function_types::function_arity<foo_type>::value << std::endl;
    std::cout << typeid(boost::mpl::at_c<boost::function_types::parameter_types<foo_type>,1>::type).name() << ",";
    std::cout << typeid(boost::mpl::at_c<boost::function_types::parameter_types<foo_type>,2>::type).name() << ",";

    return 0;
}
keineahnung2345
  • 2,635
  • 4
  • 13
  • 28
Kornel Kisielewicz
  • 55,802
  • 15
  • 111
  • 149
  • Believe me, I have tried every variant using BOOST_TYPEOF(&bar::foo) that I can think of. I'm hoping someone can post a small, working program, like the one in the question. – Jive Dadson Jan 29 '10 at 20:56
  • Most people do. I've been a professional programmer since 1971, and I've learned that it cannot hurt to spell things out. Thanks for your help. – Jive Dadson Jan 29 '10 at 22:26
  • @Jive, no problem, I don't get anything out of it anyway -- although this gave me an inclination to try to do that full C++ reflection library thing again ;> – Kornel Kisielewicz Jan 29 '10 at 22:27
  • @Kornel You've got to admit, it's pretty obscure. My dream is a ++C++ that's what C++ would be if Bjarne knew then what he knows now. Without the requirement that C++ be a superset of C, a requirement that has since been dropped, all options would be open. For one thing, compile-time introspection would not have to be done through hacks with template constructs. I've got some ideas, but whom am I kidding? That's one more thing I'll never do. – Jive Dadson Jan 29 '10 at 22:44
  • @Jive, yeah I'll admit it. And yes, I'd dream that C++ finally dropped backwards compatibility to C++ -_-. If you want a language that is ++C++ then try D. – Kornel Kisielewicz Jan 29 '10 at 23:00
  • @Jive -- BTW, accept the answer if you're satisfied with it ;) – Kornel Kisielewicz Jan 29 '10 at 23:02
1

Kornel Kisielewicz nailed it. Here it is with the solution separated from the test-messages.

#include <boost/function_types/function_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/typeof/std/utility.hpp>
#include <iostream>

struct bar {
    int foo(int, char) { return 0; }
};

int main() {

    typedef BOOST_TYPEOF(&bar::foo) 
        foo_type;
    int arity = boost::function_types::function_arity<foo_type>::value;
    typedef boost::mpl::at_c<boost::function_types::parameter_types<foo_type>,1>::type
        arg1;
    typedef boost::mpl::at_c<boost::function_types::parameter_types<foo_type>,2>::type
        arg2;

    std::cout << typeid(foo_type).name() << std::endl;
    std::cout << arity << std::endl;
    std::cout << typeid(arg1).name() << ",";
    std::cout << typeid(arg2).name() << std::endl;
    return 0;
}
Jive Dadson
  • 16,680
  • 9
  • 52
  • 65
1

This can be done with newer boost lib(callable traits, bonus: it works with lambdas also).

I have also added the another printout with a human readable output, although not sure if the question demands it.

#include <boost/mp11.hpp>
#include <boost/callable_traits.hpp>
#include <iostream>
#include <type_traits>
#include <boost/type_index.hpp>
using namespace std;
using namespace boost::mp11;
using namespace boost::typeindex;
namespace ct = boost::callable_traits;

struct bar {
    int foo(int, char) { return 0; }
};

int main() {

    using Fn = decltype(&bar::foo);
    cout << typeid(Fn).name() << endl;
    cout << tuple_size<ct::args_t<Fn>>::value << endl; // includes implicit this
    cout << typeid(mp_at_c<ct::args_t<Fn>,0>).name() << ",";
    cout << typeid(mp_at_c<ct::args_t<Fn>,1>).name()  << endl;
    cout << "Human readable" << endl;
    cout << type_id<Fn>().pretty_name() << endl;
    cout << tuple_size<ct::args_t<Fn>>::value << endl; // includes implicit this
    cout << type_id<mp_at_c<ct::args_t<Fn>,0>>().pretty_name() << ",";
    cout << type_id<mp_at_c<ct::args_t<Fn>,1>>().pretty_name() << endl;
    return 0;
}

gcc output:

M3barFiicE

3

3bar,i

Human readable

int (bar::*)(int, char)

3

bar,int

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 1
    Or have a look at my own (production grade, fully documented) alternative here: https://github.com/HexadigmAdmin/FunctionTraits . I've placed your own code above with trivial changes only (I think you may have intended) with mine right after it here: https://godbolt.org/z/o3csG94nb. Output is identical. – Larry May 30 '23 at 18:03