-1

I have free functions foo which are overloaded for user defined types X as follows (C being a library type calling foo):

template <typename C>
void foo(C&, const X&) {...}

I am able to determine at compile-time whether there exists an overload for a specific type X:

template <typename... Args>
auto foo_exists(int) -> decltype(std::bind<void(*)(Args...)>(&foo, std::declval<Args>()...), std::true_type());

template <typename... Args>
auto foo_exists(char) -> std::false_type;

struct Caller
{
    template <typename T>
    void call(const T& x)
    {
        static_assert(decltype(foo_exists<decltype(*this), const T&>(0))::value, "");
    }
};

Now assume the following class hierarchy with foo overloads for Base and Derived:

struct Base{};
struct Derived : Base {};
struct Leaf : Derived{};

template <typename C>
void foo(C&, const Base&) { std::cout << "Base" << std::endl; }

template <typename C>
void foo(C&, const Derived&) { std::cout << "Derived" << std::endl; }

How can I determine that when invoking foo(..., Leaf()), the const Derived& overload will be called?

Generically speaking:

I want to test for the exact type of foo in order to find out whether a function overload for a specific type X. exists; if it does not exist, I want to know if other function overloads for a base types of X exist and if yes, which one would be called when passing an argument of type const X& to it.

The "which" information should contain the base type, which for the above example would be Derived (and not Base).

live example

m.s.
  • 16,063
  • 7
  • 53
  • 88
  • @ildjarn I read that other question, however I thought that maybe my restriction to base-class overloads would enable what I need – m.s. Jul 18 '16 at 07:54
  • The fundamental limitation is the lack of compile-time introspection for overload sets; the types being used as arguments have no bearing AFAICT. – ildjarn Jul 18 '16 at 07:57

1 Answers1

0

You can duplicate the function signatures and write a custom trait to detect which one will be called, like so:

template <typename T>
struct S {
    static Base mock_foo(const Base&);
    static Derived mock_foo(const Derived&);
    static void mock_foo(...);

    // Base if Base overload will be called, Derived if Derived overload
    // will be called, void if neither
    using type = decltype(mock_foo(std::declval<T>()));
}; 

http://coliru.stacked-crooked.com/a/b72655b770becc15

I'm not sure if it's possible to do this "automatically", i.e., without typing out a custom trait this way. I would guess that the answer is no, it would require some sort of reflection support in the core language.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • unfortunately I cannot enumerate all signatures in my library as the overloads of `foo` are user-defined – m.s. Jul 18 '16 at 06:49
  • @m.s. I doubt it is possible to implement such a trait without language support then. But let's see if someone proves me wrong. – Brian Bi Jul 18 '16 at 06:51
  • I fear you are right, see this question: http://stackoverflow.com/questions/35561453/determining-which-overload-was-selected I thought that maybe my restriction to base-class overloads would enable this – m.s. Jul 18 '16 at 06:52