Руководство по выведению шаблонов - это шаблоны, связанные с классом шаблона, которые сообщают компилятору, как перевести набор параметров (и их типы) в аргументы шаблона.
Самый простой пример - это std::vector
и его конструктор, который принимает пару итератора.
template<typename Iterator>
void func(Iterator first, Iterator last)
{
vector v(first, last);
}
Компилятор должен выяснить, какой тип vector<T>
T
будет. Мы знаем, что такое ответ; T
должен быть typename std::iterator_traits<Iterator>::value_type
. Но как мы можем сообщить компилятору без , чтобы набрать vector<typename std::iterator_traits<Iterator>::value_type>
?
. Вы используете руководство по выводу:
template<typename Iterator> vector(Iterator b, Iterator e) ->
vector<typename std::iterator_traits<Iterator>::value_type>;
Это говорит компилятору, что , когда вы вызываете конструктор vector
, соответствующий этому шаблону, он выдает специализацию vector
, используя код справа от ->
.
Вам нужны справочники, когда вычитание типа из аргументы не основаны на типе одного из этих аргументов. Инициализация vector
из initializer_list
явно использует vector
's T
, поэтому ему не нужно руководство.
Левая сторона необязательно указывает конструктор. Способ его работы состоит в том, что если вы используете вычет конструктора шаблона для типа, он соответствует аргументам, которые вы передаете во всех руководствах по вычитанию (фактические конструкторы первичного шаблона предоставляют неявные руководства). Если есть совпадение, он использует это, чтобы определить, какие аргументы шаблона должны указывать на тип.
Но как только этот вывод будет выполнен, как только компилятор определит параметры шаблона для типа, инициализация объекта этого типа происходит так, как будто ничего из этого не произошло. То есть выбранное руководство вычитания не должно соответствовать выбранному конструктору .
Это также означает, что вы можете использовать направляющие с агрегатами и агрегатной инициализацией:
template<typename T>
struct Thingy
{
T t;
};
Thingy(const char *) -> Thingy<std::string>;
Thingy thing{"A String"}; //thing.t is a `std::string`.
. Руководство по вычитанию используется только для определения инициализированного типа. Фактический процесс инициализации работает точно так же, как и раньше, после того, как это было сделано.
Хорошей новостью является то, что вы можете выбросить функцию SUMPRODUCT и заменить ее на пару функций COUNTIFS . COUNTIFS может использовать полные ссылки столбцов без ущерба и намного эффективнее, чем SUMPRODUCT, даже с диапазонами ячеек SUMPRODUCT, ограниченными экстентами данных.
В N2 в качестве стандартной функции
=COUNTIFS(B:B, B2,M:M, "<"&M2)+COUNTIFS(B$2:B2, B2, M$2:M2, M2)
Заполните, если необходимо,
Решение, основанное на OP
Изучая ваше сообщение, требующее опубликовать какие-либо альтернативы, я заинтересовался решением, основанным на вашем первоначальном подходе, с помощью функции SUMPRODUCT
. ИМО это может показать правильный путь для искусства :
Прикладной метод
Получить
Пример формулы, например в ячейке N5:
=SUMPRODUCT(($B$2:$B$38705=$B5)*($M$2:$M$38705<=$M5))-COUNTIFS($B5:$B$38705,$B5,$M5:$M$38705,$M5)+1
P.S.
Конечно, я согласен с вами, предпочитая вышеприведенное решение: +)