Ленивый тип-вывод для карри функций - PullRequest
0 голосов
/ 06 февраля 2019

В следующем примере вывод типа завершается неудачно для вызова mkPair2:

#include <functional>

template <class A, class B>
struct Pair {
  A left; B right;
};

template <class A, class B>
Pair<A,B> mkPair1 (A left, B right) {
  return (Pair<A,B>) { left, right };
}

template <class A, class B>
std::function<Pair<A,B>(B)> mkPair2 (A left) {
  return [left] (B right) {
    return (Pair<A,B>) { left, right };
  };
}

Pair<int, char> ex1 = mkPair1 (2, 'a');
Pair<int, char> ex2 = mkPair2 (2) ('a');

Проблема в том, что mkPair2 имеет два аргумента шаблона, но вызов (2) предоставляет толькоодин из них, поэтому компилятор немедленно поднимает руки и решает, что программа неоднозначна, хотя второй тип может быть выведен из следующего вызова ('a').

Это можно решить, дав компиляторутипы вручную mkPair2<int,char> (2) ('a'), но при такой необходимости держать компилятор за руку очень быстро стареет.

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

Ответы [ 2 ]

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

В дополнение к ответу @ NathanOliver, вы можете заставить его работать и для C ++ 11, создав собственный эквивалент лямбды-выражения:

template <class A>
struct X {
    A left;
    X(A left) : left(left) {}

    template <class B>
    Pair<A,B> operator()(B right) {
        return Pair<A,B>{left, right};
    }
};

Тогда:

template <class A>
X<A> mkPair2(A left) {
    return X<A>(left);
}
0 голосов
/ 06 февраля 2019

, хотя второй тип может быть выведен из следующего ('a') вызова.

Да, это может быть выведено, но правила C ++ не допускают этого,Вывод типа происходит только с параметрами функции.Поэтому, если вам не хватает параметра функции для параметра шаблона, вам нужно указать его самостоятельно.

При этом вычитание типа автоматического возврата в C ++ 14 и общие лямбда-выражения избавят вас от необходимости что-либо указывать.Вы можете переписать код как

template <class A, class B>
struct Pair {
  A left; B right;
};

template <class A, class B>
auto mkPair1 (A left, B right) {
  return Pair<A,B>{ left, right };
}

template <class A>
auto mkPair2 (A left) {
  return [left] (auto right) {
    return Pair<A, decltype(right)>{ left, right };
  };
}

Pair<int, char> ex1 = mkPair1 (2, 'a');
Pair<int, char> ex2 = mkPair2 (2) ('a');

, и все будет выведено для вас.Он также возвращает лямбда-объект вместо std::function, поэтому вы избегаете затрат на стирание типов, используемых std::function.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...