Включение автоматического вывода типа аргумента шаблона на основе значения этого аргумента по умолчанию - PullRequest
4 голосов
/ 14 апреля 2019

Вот что я хочу сделать:

#include <vector>

template <class ContainerType, typename ComparatorType>
void f(
    ContainerType c1,
    ComparatorType comp = 
    [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;})
{
}

int main()
{
    std::vector<int> a{1, 2};
    f(a);
    return 0;
}

Но это не работает: could not deduce template argument for 'ComparatorType'.

Использование прокси-функции вместо фактического значения аргумента по умолчанию работает, но кажется слишком многословным, разве нет лучшего способа? Не говоря уже о том, что это не то же самое, поскольку теперь я не могу просто заменить компаратор по умолчанию своим собственным без изменения имени функции в коде клиента.

#include <vector>

template <class ContainerType, typename ComparatorType>
void f(
    ContainerType c1,
    ComparatorType comp)
{
}

template <class ContainerType>
void f2(ContainerType c)
{
    f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}

int main()
{
    std::vector<int> a{1, 2};
    f2(a);
    return 0;
}

Ответы [ 2 ]

5 голосов
/ 14 апреля 2019

без изменения имени функции в коде клиента.

Вы можете просто перегружать шаблоны функций.Нет необходимости использовать другое имя.

template <class ContainerType, typename ComparatorType>
void f(
    ContainerType c1,
    ComparatorType comp)
{
}

template <class ContainerType>
void f(ContainerType c)
{
    f(c, [](const typename ContainerType::value_type& l, const typename ContainerType::value_type& r) {return l < r;});
}

Невозможно сделать аргумент функции по умолчанию способствующим выводу аргумента шаблона.Это не разрешено, потому что это поднимает некоторые трудные для разрешения вопросов в процессе дедукции.

4 голосов
/ 14 апреля 2019

Вывод из шаблона выполняется перед рассмотрением аргументов по умолчанию.Кроме того, лямбды не допускаются в неоцененных операндах.

Сначала можно назначить функцию по умолчанию для переменной.Тогда вы можете разобрать его тип.Например:

auto default_functor = [](int x){ return x > 0; };

template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
  return f(x);
}

Теперь вы можете использовать функцию как обычно:

bool even(int x)
{
  return x % 2 == 0;
}

struct Odd {
  bool operator()(int x) const
  {
    return x % 2 == 1;
  }
};

void g()
{
  function(1); // use default functor
  function(1, even); // use a free function
  function(1, Odd{}); // use a function object
  function(1, [](int x){ return x < 0; }); // use another lambda
}

Вам не нужно явно указывать тип.


Примечание. Согласно @ StoryTeller это может привести к нарушению ODR, если вы используете его в заголовке.В этом случае вы можете использовать именованный тип функтора:

struct Positive {
    constexpr bool operator(int x) const
    {
        return x > 0;
    }
};

inline constexpr Positive default_functor{};

template <typename T, typename F = decltype(default_functor)>
auto function(T x, F f = default_functor)
{
  return f(x);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...