Как передать функцию перегрузки, заданную в качестве параметра шаблона - PullRequest
0 голосов
/ 24 апреля 2020

У меня есть такой код:

template<auto Function>
struct Bind
{
    template<typename... Args>
    static auto func(Args&&... args)
    {
        return std::invoke(Function, args...);
    }
};

struct F
{
    int i;
    auto foo(int ii){ i = ii; }
};

int main()
{
    F f{};
    Bind<&F::foo>::func(f, 5); //set `i` to 5
    return Bind<&F::i>::func(f); //return 5
}

Но теперь мне нужно добавить новую функцию int F::foo();, и мне все еще нужно иметь возможность вызывать обе функции с func, например:

template<typename TBind>
auto bar(F f)
{
    TBind::func(f, 5); // calls `void F::foo(int)`
    return TBind::func(f); // calls `int F::foo()`
}

Возможно сделать это в C ++ 17 и по-прежнему использовать auto Function?

(C ++ 20 может иметь пользовательские типы в качестве аргумента шаблона значения, которые решают эту проблему)

1 Ответ

0 голосов
/ 24 апреля 2020

C ++ 17 не может передавать пользовательские объекты в качестве параметров шаблона, но позволяет передавать указатели на него.

С помощью небольшой вспомогательной функции мы можем легко это сделать:

#include <functional>

//this will dereferece all arguments in form of `T*` or return it without change
template<typename T>
auto optDeref(T t) { return t; }
template<typename T>
auto optDeref(T* t) -> T& { return *t; }

template<auto Function>
struct Bind
{
    template<typename... Args>
    static auto func(Args&&... args)
    {
        return std::invoke(optDeref(Function), std::forward<Args>(args)...);
    }
};

struct F
{
    int i;
    void foo(int ii){ i = ii; }
    int foo() { return i; }
};

template<typename TBind>
int bar(F f)
{
    TBind::func(f, 5);
    return TBind::func(f);
}

struct
{
    template<typename... Args>
    auto operator()(F& f, Args&&... args) const -> decltype(auto) { return f.foo(args...); }
} f_overload;

struct
{
    auto operator()(F& f) const { return f.foo(); }
    auto operator()(F& f, int i) const { return f.foo(i); }
} f_overloadLimited;

int main()
{
    F f{};
    return Bind<&F::i>::func(f) + bar<Bind<&f_overload>>(f) + bar<Bind<&f_overloadLimited>>(f);
}


Рабочий пример :

https://gcc.godbolt.org/z/HMuxN_ (сейчас есть проблемы с VS (2020-04-24) и они не показывают корректный успех для него)

...