はじめに
[追記] 推論させる方法はありませんでした。なので、この記事は「unique_ptr のカスタムデリータにラムダ式を使う際、なぜ推論してくれないか」の紹介になります。
通常、std::unique_ptr
のカスタムデリータにラムダ式を使うときは、以下のように書くと思われます。
#include <iostream>
#include <memory>
struct my_struct {
void finalize()
{
std::cout << "finalized!";
}
};
int main()
{
auto lambda = [](auto * ptr) {
ptr->finalize();
delete ptr;
};
std::unique_ptr<my_struct, decltype(lambda)> a{ new my_struct };
} // output: finalized!
このラムダ式には、名前を付ける必要があります。推論してくれません。
なぜ推論しないのか
検索したところ、ここを見つけました。理由を要約すると、どうやら、これは配列を引数に取った場合にポインタと推論してしまうからだそうです。一応、例を載せておきます。
#include <iostream>
#include <boost/type_index.hpp>
template <typename T>
struct my_struct {
my_struct(T) {};
void check_type()
{
std::cout << boost::typeindex::type_id_with_cvr<T>().pretty_name() << std::endl;
}
};
int main(){
int i[10];
my_struct{i}.check_type(); // output: int*
}
推論させる方法(未定義)
上記のリンクにあるように、推論ガイドを自分で書けば推論してくれます。推論してほしい型の最初の引数は、配列を使う場合には my_struct[]
です。(配列と普通のものを、同時には使えなそうです)
[追記] しかし、これは未定義動作です。std名前空間には推論ガイドを書いてはいけません。
#include <iostream>
#include <memory>
struct my_struct {
void finalize()
{
std::cout << "finalized!" << "\n";
}
};
namespace std { // wandbox の clang では std::__1 でできました
// 推論補助宣言 カスタムデリータ用
template <class T>
unique_ptr(my_struct *, T)
->unique_ptr<my_struct, T>;
// ->unique_ptr<my_struct[], T>; 配列の場合
} // namespace std
int main()
{
std::unique_ptr a{ // 推論!
new my_struct, [](auto * ptr) {
ptr->finalize();
delete ptr;
}
};
} // output: finalized!
おわりに
std::make_unique
のほうも考えましたが、これはカスタムデリータをサポートしていないため、上記でよさそうです。繰り返しになりますが、配列と同時に使う場合には使用できないと思われます。配列のみの場合は、こんな感じになりそうです。( warning の山は無視してください... )
[追記] unique_ptr のカスタムデリータにラムダ式を使う際、推論させる方法はなさそうです。std名前空間は、特に断りがない限り自分で宣言または定義などを追加してはいけないようです。上記にあるように、移植性にかけるので、やらないようにしましょう!