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
fof typeFis Callable for argument typesArgTypesand return typeRif 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:Fshall beCopyConstructible.fshall be Callable (20.8.11.2) for argument typesArgTypesand return typeR. (snip)
関連URL