咖喱函数的惰性类型推断

时间:2019-02-06 20:04:47

标签: c++ type-inference

在以下示例中,对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 :(得分:7)

  

即使可以从以下('a')调用中推断出第二种类型。

是的,可以推断出来,但是C ++的规则不允许这样做。类型推导仅在函数参数中发生。因此,如果缺少模板参数的功能参数,则需要自己指定。

也就是说,C ++ 14的自动返回类型推断和通用lambda可以使您不必指定任何内容。您可以将代码重写为

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');

一切都会为您推演。它还返回lambda对象,而不是std::function,因此避免了std::function使用的类型擦除的开销。

答案 1 :(得分:2)

除了@NathanOliver的答案外,您还可以自己创建等效于通用lambda的方法,使其也适用于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);
}