Определите, какая перегрузка будет вызываться при передаче типа в качестве ссылки

У меня есть бесплатные функции foo, которые перегружены для определенных пользователем типов X следующим образом (C является библиотечным типом, вызывающим foo):

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

Я могу определить во время компиляции, существует ли перегрузка для определенного типа 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, "");
    }
};

Теперь предположим следующую иерархию классов с перегрузками foo для Base и 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; }

Как определить, что при вызове foo(..., Leaf()) будет вызываться перегрузка const Derived&?

В общем:

Я хочу проверить точный тип foo, чтобы выяснить, перегружена ли функция для определенного типа X. существуют; если он не существует, я хочу знать, существуют ли другие перегрузки функций для базовых типов X, и если да, то какая из них будет вызываться при передаче ему аргумента типа const X&.

Информация «какой» должна содержать базовый тип, который для приведенного выше примера будет Derived (а не Base).

живой пример


person m.s.    schedule 18.07.2016    source источник
comment
@ildjarn Я читал этот другой вопрос, однако я подумал, что, возможно, мое ограничение на перегрузки базового класса позволит то, что мне нужно   -  person m.s.    schedule 18.07.2016
comment
Фундаментальным ограничением является отсутствие самоанализа перегруженных наборов во время компиляции; типы, используемые в качестве аргументов, не имеют значения AFAICT.   -  person ildjarn    schedule 18.07.2016


Ответы (1)


Вы можете продублировать сигнатуры функций и написать собственный трейт, чтобы определить, какой из них будет вызываться, например:

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

Я не уверен, что это можно сделать "автоматически", т.е. без ввода пользовательского признака таким образом. Я предполагаю, что ответ отрицательный, для этого потребуется какая-то поддержка отражения в основном языке.

person Brian Bi    schedule 18.07.2016
comment
к сожалению, я не могу перечислить все подписи в моей библиотеке, так как перегрузки foo определяются пользователем - person m.s.; 18.07.2016
comment
@РС. Я сомневаюсь, что тогда можно реализовать такой трейт без языковой поддержки. Но посмотрим, докажет ли кто-нибудь, что я не прав. - person Brian Bi; 18.07.2016
comment
Боюсь, вы правы, см. этот вопрос: stackoverflow.com /questions/35561453/ Я подумал, что, возможно, мое ограничение на перегрузки базового класса позволит это - person m.s.; 18.07.2016