C++11標準ライブラリ提供のstd::function
クラステンプレートにおいて、同functionオブジェクトで保持する呼び出し可能オブジェクト(callable object)の戻り値型に関するメモ。
2015-09-27追記:この制限は次期標準規格C++1z(C++17)にて修正される。id:yohhoy:20150927参照。
下記サンプルコードにおいて、オブジェクトf1
のコンストラクタ呼び出しはその要件に違反しており、厳密にC++11標準規格に従うと未定義動作(undefined behavior)を引き起こす。これは、クラステンプレート引数に与えた関数シグネチャの戻り値型R = void
に対して、関数twice
の戻り値型int
からの暗黙的な変換(int
→void
)が定義されないことによる。
#include <functional> int twice(int x) { return x * 2; } int main() { std::function<int(int)> f0( twice ); // OK std::function<void(int)> f1( twice ); // NG: int→voidへ暗黙変換不可 f0(42); f1(42); }
ただし、gcc/libstdc++など大抵の処理系では上記コードを許容し、(プログラマの期待通り)戻り値を破棄するよう動作してしまう。LLVM/libc++ではコンパイルエラーとして検知するとのこと*1。
N3337 17.6.4.11/p1, 20.8.2/p2, 20.8.11.2/p2, 20.8.11.2.1/p7より一部引用。
1 Violation of the preconditions specified in a function's Requires: paragraph results in undefined behavior unless the function's Throws: paragraph specifies throwing an exception when the precondition is violated.
2 Define
INVOKE(f, t1, t2, ..., tN, R)
asINVOKE(f, t1, t2, ..., tN)
implicitly converted toR
.
2 A callable object
f
of typeF
is Callable for argument typesArgTypes
and return typeR
if the expressionINVOKE(f, declval<ArgTypes>()..., R)
, considered as an unevaluated operand (Clause 5), is well formed (20.8.2).
template<class R, class... ArgTypes>
class function<R(ArgTypes...)>
template<class F> function(F f);
7 Requires:F
shall beCopyConstructible
.f
shall be Callable (20.8.11.2) for argument typesArgTypes
and return typeR
. (snip)
関連URL