std::function の Const の正確性の問題

const 型修飾子は、C++ 言語設計の宝石の 1 つです。この機能を取り囲むように、"const const を防止するための「正しさ」の練習 オブジェクトが変異するのを防ぎます。 const ほとんどのクラスの実装では、正確性のルールに従うのは簡単ですが、型消去のあるクラスについては注意が必要です。残念ながら、標準ライブラリ タイプ std::function 型消去によって実装されます。そして、近視のために、const-correctness ルールに従わない行儀の悪い市民の 1 つになります。

問題

std::function 1 つの const メンバー operator() があります 、それでも基になる関数を変更できます。たとえば、

const std::function<int()> f {[x=0]() mutable { return ++x; }};
f(); // returns 1
f(); // returns 2

ドキュメント N43481 この懸念を最初に公式化した。

修正

function の実装 のようなクラスには、const 用に個別の特殊化が必要です。 const 以外 .

template<class Sig> class function; // not defined

template<class R, class... Args>
  class function<R(Args...)>;

template<class R, class... Args>
  class function<R(Args...) const>;

operator() const の 特殊化には const の注釈を付ける必要があります 、しかし const のコンストラクター 特殊化は変更可能な関数オブジェクトを受け入れません.

function<int() const> f1 {[x=0]() { return x; }};
f1() // ok;

function<int() const> f2 {[x=0]() mutable { return ++x; }}; // Does not compile

一方、operator()const の 特殊化には const がありません 型署名であるため、const を呼び出すことはできません そのような関数のバージョン:

function<int()> f1 {[x=0]() mutable { return ++x; }};
f1(); // ok

const function<int()> f2 {[x=0]() mutable { return ++x; }};
f2(); // Does not compile

未来

std::function とは思わない 下位互換性を損なうような変更を加えることはできません。この記事の執筆時点 (2019 年 12 月) で、私の賭けは提案された std::unique_function にあります。 2 、これは std::function のドロップイン置換です これにより、他の機能の中でも const-correctness バグが修正されます。標準で代替案ができたら std::function std::auto_ptr のように非推奨にすることができます .それまでの間、いつでも unique_function を実装できます Github でそれを実装するための小さなライブラリがあります。

<オール>
  • std::function を同時実行に対して安全にする↩
  • P0228R3 unique_function:移動のみの std::function↩