質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

2475閲覧

std::unique_ptrのようなクラスを自作したい。

ssssskkkkk

総合スコア20

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2018/07/30 10:58

std::unique_ptrのようなクラスを自作したいと思っています。
具体的には以下のようなことです。

c++

1class C4 { 2public: 3 static void Delete(C4*) {} 4}; 5 6class C5 : public C4 { 7public: 8 static void Delete(C4*) {} 9}; 10 11void g2() { 12 using C = unique_ptr<C4, decltype(&C4::Delete)>; 13 using D = unique_ptr<C5, decltype(&C4::Delete)>; 14 C c = D(new C5(), &C5::Delete); 15}

しかし、単純に実装すると、以下のコードのg()関数の
C c = D(new C2(), &C2::Delete);
の部分でエラーが出てしまいます。
おそらくカスタムデリータの関連でエラーが出ているとは思うのですが、どのように実装すれば良いのかわかりません。
よろしくお願い致します。

c++

1class C1 { 2public: 3 static void Delete(C1*) {} 4}; 5 6class C2 : public C1 { 7public: 8 static void Delete(C1*) {} 9}; 10 11template<class T, class U> 12class C3 { 13public: 14 C3(T* t, U u) 15 : 16 t_(t), 17 u_(u) 18 { 19 ; 20 } 21private: 22 T* t_; 23 U u_; 24}; 25 26void g() { 27 using C = C3<C1, decltype(&C1::Delete)>; 28 using D = C3<C2, decltype(&C1::Delete)>; 29 C c = D(new C2(), &C2::Delete); 30}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

こんにちは。

既にBAでてますが、ちょっとだけ補足です。

C3<C1>とC3<C2>では型が異なるから代入(このケースではコンストラクト)できないです。
なので、C3<C1>にはC3<C2>を受け取るコンストラクタが必要になります。
目標がstd::unique_ptrならば、yumetodoさんが例示されているようなムーブ・コンストラクタを実装することになります。

次にC2がC1を継承しているので、C3<C2>をC3<C1>へムーブして良いですが逆は危険ですね。なので、互換性のない代入を禁止しないと危険です。(yumetodoさんのサンプルはstatic_castしているのでダウンキャストしてもエラーにならないです。static_castを外すだけで行けそうな気がします。でも、エラーメッセージの解読たいへんそう。clangはかなり良いですがgccはなかなか悲惨です。)

更にムーブ代入演算子も必要になるでしょうから、なかなか手間がかかりそうです。

投稿2018/07/30 12:17

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2018/07/30 12:27

>static_castを外すだけで行けそうな気がします。 多分だめです。unique_ptrを規格通り実装するのであれば、SFINAEでオーバーロードから外さないとだめで、単にstatic_castをなくすだけでは要求を満たしません(いずれにせよstatic_castはいらんかった)
yumetodo

2018/07/30 12:35

まあ実質unique_ptrを規格通りすべて実装しきらないとだめでしょうから、大変ですね。もちろんstd::vectorを自力実装するのに比べれば遥かに楽ですが。
Chironian

2018/07/30 15:39

なるほど。確かに配列はSFINAEを使って「配列でないこと」をチェックしないとだめそうな感じがしますね。
guest

0

ベストアンサー

コンストラクタが足りていないからです。
unique_ptr::コンストラクタ - cpprefjp C++日本語リファレンス
の7番目。

エラーチェックとオーバーロード候補から外すためのもろもろを除くと

cpp

1#include <memory> 2class C1 { 3public: 4 static void Delete(C1*) {} 5}; 6 7class C2 : public C1 { 8public: 9 static void Delete(C1*) {} 10}; 11 12template<class T, class U> 13class C3 { 14public: 15 using pointer = T*; 16 using deleter_type = U; 17 C3(T* t, U u) 18 : 19 t_(t), 20 u_(u) 21 { 22 ; 23 } 24 template <class T2, class U2> 25 C3(C3<T2, U2>&& u) noexcept : t_(static_cast<pointer>(u.release())), u_(u.get_deleter()) 26 {} 27 ~C3() 28 { 29 delete t_; 30 } 31 deleter_type& get_deleter() noexcept { return u_; } 32 const deleter_type& get_deleter() const noexcept { return u_; } 33 pointer get() const noexcept { return t_; } 34 pointer release() noexcept 35 { 36 auto re = get(); 37 t_ = nullptr; 38 return re; 39 } 40private: 41 T* t_; 42 U u_; 43}; 44 45void g() { 46 using C = C3<C1, decltype(&C1::Delete)>; 47 using D = C3<C2, decltype(&C1::Delete)>; 48 C c = D(new C2(), &C2::Delete); 49}

https://wandbox.org/permlink/0d1E0ffg5oVoUs6D

こんな感じでしょうか。

ちゃんと書くときは真面目にSFINAEを書いてください。cpprefjpの「以下の条件を満たさない場合、この関数はオーバーロード解決の候補から外れる:」の部分を参照。

投稿2018/07/30 11:25

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ssssskkkkk

2018/07/30 11:57

無事にやりたいことが実現できました。 SFINAEは何度か勉強して諦めてしまったのですが、この機会にまた学び直したいと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問