Почему я не могу создать шаблонную функцию с необязательным аргументом UnaryPredicate? - PullRequest
0 голосов
/ 21 февраля 2019

Я пытаюсь создать шаблонную функцию с необязательным аргументом, и мне трудно понять, почему компиляция не удалась.Это мой тестовый (надуманный) код:

#include <iostream>
#include <vector>

template <class UnaryPredicate>
int GetCountIf(std::vector<int> v, UnaryPredicate pred = [](auto) { return true; }) {
  int count=0;
  for (auto i: v) {
    if (pred(i)) {
      count++;
    }
  }
  return count;
}

int main() {
  auto v = std::vector<int>{0, 1, 2, 3, 4, 5};
  std::cout << "NumOddElements=" << GetCountIf(v, [](auto val) { return (val % 2 == 1); }) << '\n';
  // std::cout << "NumElements=" << GetCountIf(v) << '\n';
}

Код компилируется, только если я вызываю GetCountIf() с обоими аргументами.Если я попытаюсь передать ему только 1 аргумент, компиляция завершится с ошибкой:

main.cpp: 18: 34: ошибка: нет соответствующей функции для вызова GetCountIf
std ::cout << "NumElements =" << GetCountIf (v) << '\ n';^ ~~~~~~~~~ main.cpp: 5: 5: note: шаблон кандидата игнорируется: невозможно определить аргумент шаблона 'UnaryPredicate' int GetCountIf (std :: vector v, UnaryPredicate pred = {return true;}) {^ 1 сгенерирована ошибка. </p>

Когда компилятор сталкивается с вызовом GetCountIf только с одним аргументом, почему он не может определить тип необязательной лямбды?Если я явно указываю тип предиката следующим образом, он работает:

template <typename T, class UnaryPredicate = std::function<bool(T)>>
int GetCountIf(std::vector<T> v, UnaryPredicate pred = [](T) { return true;}) {
  ...
}

Почему это работает?

(я использую C ++ 14)

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Аргумент по умолчанию участвует в выводе типа, поэтому поведение, которое вы наблюдаете.

В качестве альтернативы вы можете создать перегрузки:

template <class UnaryPredicate>
int GetCountIf(const std::vector<int>& v, UnaryPredicate pred) {
    int count = 0;
    for (auto i: v) {
        if (pred(i)) {
          count++;
        }
    }
    return count;
}

int GetCountIf(const std::vector<int>& v) {
    return GetCountIf(v, [](auto) { return true; }); // return v.size(); // :-)
}
0 голосов
/ 21 февраля 2019

Обратите внимание, что значение параметра по умолчанию не будет использоваться для вывода аргумента шаблона из параметра шаблона;что приводит к ошибке вывода аргумента шаблона, тип UnaryPredicate не может быть выведен.

См. невыгруженные контексты .

В следующемВ случаях, типы, шаблоны и нетипизированные значения, используемые для составления P, не участвуют в выводе аргументов шаблона, а вместо этого используют аргументы шаблона, которые были либо выведены в другом месте, либо явно указаны.Если параметр шаблона используется только в невыгруженных контекстах и ​​не указан явно, вывод аргумента шаблона завершается неудачей.

4) Параметр шаблона используется в типе параметра параметра функции, который имеет аргумент по умолчанию, который являетсяиспользуется в вызове, для которого выполняется вывод аргумента:

template<typename T, typename F>
void f(const std::vector<T>& v, const F& comp = std::less<T>());
std::vector<std::string> v(3);
f(v); // P1 = const std::vector<T>&, A1 = std::vector<std::string> lvalue
      // P1/A1 deduced T = std::string
      // P2 = const F&, A2 = std::less<std::string> rvalue
      // P2 is non-deduced context for F (template parameter) used in the
      // parameter type (const F&) of the function parameter comp,
      // that has a default argument that is being used in the call f(v)

и

Параметр шаблона типа не может быть выведен из типа аргумента функции по умолчанию:

template<typename T> void f(T = 5, T = 7);

void g()
{
    f(1);     // OK: calls f<int>(1, 7)
    f();      // error: cannot deduce T
    f<int>(); // OK: calls f<int>(5, 7)
}

С другой стороны, если вы укажете значение по умолчанию std::function<bool(T)> для параметра шаблона UnaryPredicate, оно будет использоваться как тип для UnaryPredicate, если аргумент дляUnaryPredicate явно не указано или не выводится.

...