C ++ 11 упрощает синтаксис шаблонной функции, вызывая разные специализации одной и той же шаблонной функции - PullRequest
1 голос
/ 08 апреля 2020

Есть несколько шаблонных функций (с одинаковыми сигнатурами), таких как:

template <typename T, typename P> void f1(T t, P p);
template <typename T, typename P> void f2(T t, P p);

Есть также несколько функций с одинаковыми логами c, которые вызывают их с разными предикатами:

template <typename T> void g1(T t)
{
    f1(t, Pred1{});
    ...
    f1(t, Pred2{});
    ...
}

// same as g1 but calls f2 instead of f1
template <typename T> void g2(T t)
{
    f2(t, Pred3{});
    ...
    f2(t, Pred4{});
    ...
}

Я попытался обобщить их, и все, что я мог придумать, это что-то вроде:

template <typename P1, typename P2, typename FP1, typename FP2, typename T>
void g(T t, FP1 fp1, FP2 fp2, P1 p1, P2 p2)
{
    fp1(t, p1);
    ...
    fp2(t, p2);
    ...
}

template <typename T> void g1(T t)
{
    g(t, f1<T, P1>, f2<T, P2>, P1{}, P2{});
}

Так что это слишком многословно, особенно с реальными типами, а не игрушечными, как в этом примере , Я должен отдельно передать каждую f() специализацию, которая вызывается в обобщенной функции g(), и я должен упомянуть каждый предикат дважды (во-первых, его тип в f-специализации, во-вторых, объект предиката в качестве отдельного параметра).

Если я уберу P1 p1, P2 p2 аргументы из g(), мне все равно придется назвать его следующим образом: g<P1, P2>(t, f1<T, P1>, f1<T, P2>)

Есть ли способ сделать его проще и избежать повторений?

Я ограничен C ++ 11 / 14.

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020

У вас не может быть параметра функции шаблона шаблона.

Способ передать перегрузку состоит в том, чтобы обернуть их в Functor.

Таким образом, ваш универсальный c g становится:

template <typename F, typename T>
void g(F f, T t)
{
    f(t, Pred1{});
    ...
    f(t, Pred2{});
    ...
}

Создание функтора проще в C ++ 14 с помощью generi c lambda:

g([](auto e, auto pred){ return f1(e, pred); }, t);

В C ++ 11 функтор более многословен (особенно с захватом):

struct F1
{
    template <typename T, typename Pred>
    auto operator()(T t, Pred pred) const {
        return f1(t, pred);
    }
};

g(F1{}, t);
1 голос
/ 08 апреля 2020

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

Например:

template <template <typename...> typename Func, typename T, typename P, typename ...Ps>
struct Caller
{
    void operator()(T t, P p, Ps ...ps)
    {
        Func<T, P>{}(t, p);
        Caller<Func, T, Ps...>{}(t, ps...);
    }
};

template <template <typename...> typename Func, typename T, typename P>
struct Caller<Func, T, P>
{
    void operator()(T t, P p)
    {
        Func<T, P>{}(t, p);
    }
};

template <template <typename...> typename Func, typename T, typename ...Ps>
void Call(T t, Ps ...ps)
{
    Caller<Func, T, Ps...>{}(t, ps...);
}

template <typename T, typename P> struct f1 {
    void operator()(T t, P p) { std::cout << "f1 " << t << ", " << p << "\n"; }
};

template <typename T, typename P> struct f2 {
    void operator()(T t, P p) { std::cout << "f2 " << t << ", " << p << "\n"; }
};

int main() {
    Call<f1>(1.0001, 2, 3.05f, 'x');
    Call<f2>(2, 3, "bar!");
}

Печать

f1 1.0001, 2
f1 1.0001, 3.05
f1 1.0001, x
f2 2, 3
f2 2, bar!

К сожалению, шаблоны функций не могут быть переданы в качестве аргументов шаблона.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...