Могут ли псевдонимы свободных функций C ++? - PullRequest
4 голосов
/ 28 марта 2019

У меня есть пространство имен с одной свободной шаблонной функцией, такой как:

namespace a
{
    template<typename T, typename K, typename H>
    void f(T t, K k, std::vector<H> h_vec = {})
    { /* body */ }
}

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

namespace b
{
    using my_specific_f = a::f<int,string,char>;
}

Что позволило бы мне обеспечить лучшее именование для функции, поскольку f является очень общим в кодовой базе, над которой я работаю (пожалуйста, имейте в виду, что здесь я приведу только упрощенные примеры). Но, к сожалению, это явно запрещено языком.

Итак, во второй попытке я попытался использовать указатель на функцию:

namespace b
{
    auto my_specific_f = &a::f<int,string,char>
}

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

В этот момент я просто сдался и просто my_specific_f перенаправил вызов в его теле на f:

namespace b
{
    void my_specific_f(int i, string s, vector<char> v = {} )
    {
        a::f(i,s,v);
    }
}

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

Осталось ли что-нибудь, что я мог бы попробовать? Возможно ли это или будет возможно в будущем выпуске стандарта?

1 Ответ

10 голосов
/ 28 марта 2019

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

auto my_really_informative_name = [](auto&&... args) -> decltype(auto) { 
                                      return f(std::forward<decltype(args)>(args)...);
                                  };

Это отлично перенаправляет параметры в f, и если его сигнатура когда-либо изменится, она все равно будет работать, поскольку лямбда может принимать любое количество аргументов.

Если вы хотите получить идеальную пересылку (квалификация noexcecpt и тип возврата по SFINAE)

auto my_really_informative_name = [](auto&&... args) noexcept(noexcept(f(std::forward<decltype(args)>(args)...))) -> decltype(f(std::forward<decltype(args)>(args)...)) { 
                                      return f(std::forward<decltype(args)>(args)...);
                                  };

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

auto my_really_informative_name = [](auto&&... args) -> decltype(auto) { 
                                      return f<int, std::string, char>(std::forward<decltype(args)>(args)...);
                                  };
...