#c #alias #typedef #using #function-templates
#c #псевдоним #typedef #использование #функция-шаблоны
Вопрос:
У меня есть пространство имен с одной свободной функцией с высоким уровнем шаблонов, такой как:
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 = amp;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.
using
предназначен для типов (псевдонимирование), а не для функций.2. @KamilCuk да, ясно, что это никогда не будет работать с
using
. Есть еще идеи?3. Просто отлично. Теперь я знаю страх.
4. Можете ли вы предоставить MCVE? Ваш второй пример компилируется как есть. gcc.godbolt.org/z/IsoJQR Решение будет зависеть от MCVE.
5. @SergeyA он компилируется, но может использоваться только версия со всеми тремя параметрами, а не версия по умолчанию с двумя.
Ответ №1:
Что вы можете сделать, так это обернуть функцию в общий лямбда-код, чтобы вы могли присвоить ей пользовательское имя. Вы можете сделать это следующим образом
auto my_really_informative_name = [](autoamp;amp;... args) -> decltype(auto) {
return f(std::forward<decltype(args)>(args)...);
};
Это отлично перенаправляет параметры в f
, и если его подпись когда-либо изменится, она все равно будет работать, поскольку лямбда-выражение может принимать любое количество аргументов.
Если вы хотите, чтобы пересылка была идеальной (без уточнения и возвращаемого типа в стиле SFINAE)
auto my_really_informative_name = [](autoamp;amp;... 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 = [](autoamp;amp;... args) -> decltype(auto) {
return f<int, std::string, char>(std::forward<decltype(args)>(args)...);
};
Комментарии:
1. С этим решением не было бы способа проверить, что
my_really_informative_name
на самом деле вызывается с правильными параметрами, которые соответствуют ожиданиям для этого имени. Извините за недоразумение. В моей неправильной первой попытке тот, который пытается использоватьusing
ключевое слово,my_specific_f
существует только для параметровint
,string
и необязательного (по умолчанию пустого)vector<char>
.2. @nyarlathotep108 К ответу добавлено решение.
3. может ли это быть достигнуто также каким-либо образом с ограничением на C 11?
4. @nyarlathotep108 Не как лямбда. Вам пришлось бы написать пользовательский функтор, подобный: coliru.stacked-crooked.com/a/1fa128ddb85f0c57