私はstd::function
(あなたも)責任があります。私は、もちろん、あなたに、std::function
に、Vittorio Romeoが説明したように、ぶら下がっている参照を返すように頼んだことを非難します。しかし、私はまた、このケースをチェックしないためにstd::function
のコンストラクタテンプレートを非難します。このテンプレートはコンパイル時に検出可能なほとんどまたはすべてのケースに存在する必要があり、結果的に診断を生成します。 (私は改善の可能な領域を指摘するためだけに "責める"という言葉を使用しています。この意味で、私は自分のunique_function
クラステンプレートの実装でこの正確なチェックを追加することを考えていなかったことを自分自身に責める)。
Let'sコンストラクタの署名を詳しく見てください。私はこの目的のために定義サイトを選びました。
template<typename R, typename... Args>
template<typename F>
std::function<R(Args...)>::function(F f);
ダングリングリファレンスをここで禁止する必要があります。 R
がF
によって返された一時的なものへの参照である場合にのみ、ぶら下がった参照がoperator()
から返されます。のは、(コンストラクタ本体の範囲で)を定義してみましょう:
using RF = decltype(f(std::forward<Args>()...));
今、私たちは次の場合にダングリング参照がfunction
のoperator()
から返されることはほぼ確実になりますがあり
std::is_reference<R>::value && ! std::is_reference<RF>::value
ただし、RF
は、ユーザー定義の変換演算子がR
のクラス型である可能性があります。この変換は依然として安全ではないかもしれませんが、私たちは決定するために十分な情報を持っておらず、一般性の面で間違いがあります。std::function
は唯一の非あいまいなパブリックアクセスすることができますので、私はここに公共の継承をのみを許可
std::is_convertible<RF *, typename std::remove_reference<R>::type *>::value
:もちろん、我々はR
の目標は、(これは上記の条件が真であると仮定している)RF
の公開基底クラスであるかどうかを検出することができました基本クラス。誰かが何らかの奇妙な理由で friend
をRF
にしていない限り。 (変換がラップ関数オブジェクトの内部で行うことができますので、これを実行する必要はおそらくありません)
が一緒にそれをすべてを置くと論理を反転、私たちはとfunction
コンストラクタの体の前に付けることができます:
using RF = decltype(f(std::forward<Args>()...));
static_assert(! std::is_reference<R>::value ||
std::is_reference<RF>::value ||
! std::is_convertible<RF *, typename std::remove_reference<R>::type *>::value,
"Using this function object would result in a dangling reference in the function call");
おそらくラムダはベクトル*を値*で返し、参照ではないからです。 –
あなたが参照を返すことが自分自身を参照している場合は、自分自身に "私は人生を参照しているそのオブジェクトは何ですか?あなたが答えることができないなら、あなたはそれをすべきではありません。 – StoryTeller
警告を有効にしてください。あなたのコンパイラはおそらく、これが悪い考えであるとあなたに叫んでいました。 – Yakk