yohhoyの日記

技術的メモをしていきたい日記

std::functionのテンプレート推論ガイド

C++17標準ライブラリで導入されたstd::functionクラステンプレートの推論ガイド(deduction guide)についてメモ。

#include <functional>

// 関数ポインタから推論
int f(int n) { return n; }
std::function f1 = f;  // OK: function<int(int)>

// ラムダ式から推論
std::function f2 = [](int n){ return n; };  // OK: function<int(int)>

// ファンクタから推論
struct Functor {
  int m_;
  int operator()(int n) const { return n * m_; }
};
std::function f3 = Functor{42};  // OK: function<int(int)>

// データメンバ/メンバ関数から推論?
struct S {
  int md = 1;
  int mf(int n) { return md += n; }
};
std::function f4 = &S::md;  // NG: ill-formed
std::function f5 = &S::mf;  // NG: ill-formed

// OK: テンプレート型引数を明示指定
std::function<int&(S&)>     f4r = &S::md;
std::function<int(S&, int)> f5r = &S::mf;
std::function<int&(S*)>     f4p = &S::md;
std::function<int(S*, int)> f5p = &S::mf;

S s;
assert(f4r( s) == 1 && f5r( s, 1) == 2);
assert(f4p(&s) == 2 && f5p(&s, 1) == 3);

C++17 23.14.13.2/p4, 23.14.13.2.1/p12-13より引用。

template<class R, class... ArgTypes>
  function(R(*)(ArgTypes...)) -> function<R(ArgTypes...)>;

template<class F> function(F) -> function<see below>;

4 [Note: The types deduced by the deduction guides for function may change in future versions of this International Standard. -- end note]

template<class F> function(F) -> function<see below>;
12 Remarks: This deduction guide participates in overload resolution only if &F::operator() is well-formed when treated as an unevaluated operand. In that case, if decltype(&F::operator()) is of the form R(G::*)(A...) cv &opt noexceptopt for a class type G, then the deduced type is function<R(A...)>.
13 [Example:

void f() {
  int i{5};
  function g = [&](double) { return i; };  // deduces function<int(double)>
}

-- end example]

データメンバ(メンバ変数)/メンバ関数へのポインタからのクラステンプレート型推論は、第1引数のオブジェクト型をポインタ/参照のいずれにするか未決であり、C++17時点では推論ガイド追加を先送りとしている。提案文書 P0433R2 より一部引用。

We suggest allowing function to deduce its template argument when initialized by a function. While it is tempting to add deduction guides for member pointers, we no longer do so as there is a question about whether the first objects should be a pointer or a reference. We are interested in committee feedback. Note that we can always add this post-c++17. Add the following deduction guide at the end of the class definition for function in §20.14.12.2 [func.wrap.func]

(snip)

Note: There are some arbitrary choices in the deductions for member pointers. We would be interested to see if the comittee agrees with having deduction guides for member pointers in addition to function pointers, and if so, whether these are the right choices.

関連URL