#c #c 20 #c -concepts #template-templates
#c #c 20 #c -концепции #шаблон-шаблоны
Вопрос:
Если вы попробуете что-то относительно простое в C 20, это приведет к бесполезному спаму с сообщениями об ошибках.
int main() {
auto as = std::vector{1,3,24,};
auto bs = std::vector{1,4,10};
auto cs = std::vector<float>{};
std::ranges::transform(as, bs, std::back_inserter(cs), std::max);
std::ranges::copy(cs, std::ostream_iterator<float>(std::cout, " "));
}
Причина в том, что std::max
это шаблонная функция, поэтому она просто не работает.
Это можно легко обойти, превратив аргумент в лямбду или создав небольшой вспомогательный функтор.
Но мне было интересно, можно ли использовать концепции C , чтобы определить, какой экземпляр шаблона нам нужен? Например, мы взламываем некоторый оператор requires, который гласит, что если аргумент функтора является шаблоном, то аргументы шаблона этого функтора должны соответствовать контейнеру value_type
.
Я сомневаюсь, что это возможно, поскольку я думаю, что точный тип функтора должен быть известен до разрешения перегрузки шаблона и проверки ограничений, другими словами, нет «обратного распространения» информации от концепций к callsite.
Но я не уверен, поэтому решил спросить.
Если вы хотите знать, что я пробовал, вот мой код, но он очень сломан, я не способен писать код аргументов шаблона шаблона…
Но в любом случае я надеюсь, что это иллюстрирует идею…
template<typename C, typename F>
struct xtransform
{
xtransform(Camp; c, F f) : c_(c), f_(f){}
void operator()(){
}
C c_;
F f_;
};
template<typename C, template<typename> typename F, typename FArg>
requires requires {
std::is_same_v<typename C::value_type, FArg>;
}
struct xtransform<C, F<FArg>>
{
xtransform(Camp; c, F<FArg> f) : c_(c), f_(f){}
void operator()(Camp; c, F<FArg> f){
}
C c_;
F<FArg> f_;
};
Комментарии:
1. Я сомневаюсь, что это возможно, поскольку я думаю, что точный тип функтора должен быть известен до того, как разрешение перегрузки шаблона и проверка ограничений будут выполнены правильно. Имя
std::max
называет шаблон. Вы не можете получить от этого конкретную вещь. Я думаю, это можно было бы исправить, если бы была добавлена перегрузка, которая принимает параметр шаблона шаблона.2. @NathanOliver в вашем последнем предложении говорится об изменениях языка или изменениях в моем коде? Потому что это то, что, я думаю , я пытался сделать.
3. Не изменение языка, а изменение стандартной библиотеки. По крайней мере, я думаю, что это можно исправить с помощью изменения библиотеки. У меня есть некоторые сомнения, поскольку я все еще думаю, что вам нужен конкретный объект, переданный функции.
4. @NathanOliver: параметры шаблона шаблона должны быть шаблонами классов / псевдонимов; шаблоны функций просто не что иное, как во время (их собственного!) Разрешения перегрузки.
5. @NathanOliver Я думаю, что самым простым изменением библиотеки было бы сделать
std::max
neibloid, хотя это нарушает существующий код.
Ответ №1:
Нет.
std::max
называет функцию шаблона. Имена функций шаблона с неполными списками параметров шаблона превращаются в функции во время разрешения перегрузки. Разрешение перегрузки требует преобразования имени функции в указатель на фиксированную сигнатуру или вызова с ()
помощью s .
Концепции не помогают.
Теперь вы можете использовать более старый трюк; перегрузите свою функцию, которая принимает указатель на функцию в неразведенном контексте. Когда я пишу ручные типы, похожие на функции std, я добавляю R(*)(Args...)
перегрузку именно по этой причине; это позволяет разрешать перегрузку, когда есть перегрузка, типы которой точно совпадают.
Но это не основано на концепции.
Комментарии:
1. Привет, вы когда-нибудь приводили пример своего решения в каком-нибудь другом ответе SO?
2. @nosense, наверное? Я написал здесь кучу замен функций std. Однако не знаю, какой именно.