Позволяют ли концепции C 20 исправлять шаблонную функцию как проблему аргумента шаблона?

#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. Однако не знаю, какой именно.