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

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

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

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

Q&A

解決済

4回答

5047閲覧

templateを使って異なるクラスのインスタンスを作成したい

hoge_beginner

総合スコア16

C++

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

0グッド

0クリップ

投稿2016/05/24 04:12

###前提・実現したいこと
異なる型のインスタンスを作成する関数を作成しています。
作成する型が異なる以外はすべて処理が同じためtemplate関数を使用して実装を共通化しようとしているのですが、内部で使用する型をテンプレートで指定する方法が分かりません。
引数や戻り値でtemplate引数を使用しない場合、template関数は使用できないのでしょうか?

###該当のソースコード

C++

1template<typename TClass>std::shared_ptr<SuperClass> Create(type) 2{ 3return std::make_shared<TClass>() 4} 5

TClassはSuperClassを継承している想定です。
typeでTClassの型を動的に切り替えたいと考えています。
たとえばtype-AならClassAのインスタンスを、type-BならClassBのインスタンスを作成するような感じです。

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

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

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

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

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

yohhoy

2016/05/24 07:19

生成するインスタンス型は、パラメータtypeで実行時に指定したいという事でしょうか?テンプレート引数に型を与えるという事は、コンパイル時に型を決めることですから、要求自体が矛盾していませんか?
hoge_beginner

2016/05/24 09:17

typeで実行時に型を指定できないかと考えています。 Create関数内でtypeを使ってswitch,caseをすれば実現できるのですが、今後typeが追加される可能性があり極力Create関数を変更しないで対処できないか考えている次第です。
guest

回答4

0

「今後typeが追加される可能性があり極力Create関数を変更しないで対処」とのことなので、Boostライブラリなども使えば実現可能ではあります。(使わなくても書けますがさらに面倒)

クラスが増えてもDrivedBを増やすだけでメンテナンス可能です。が、そこまでする価値があるかは状況次第でしょうね。

c++

1#include <cassert> 2#include <memory> 3#include <iostream> 4#include <boost/mpl/vector.hpp> 5#include <boost/mpl/for_each.hpp> 6namespace mpl = boost::mpl; 7 8// 基底クラスB 9struct B { virtual void f() = 0; }; 10// Bから派生したクラスX,Y,Z 11struct X : B { void f() { std::cout << "I'm X" << std::endl; } }; 12struct Y : B { void f() { std::cout << "I'm Y" << std::endl; } }; 13struct Z : B { void f() { std::cout << "I'm Z" << std::endl; } }; 14// B派生クラスの型リスト 15using DrivedB = mpl::vector<X, Y, Z>; 16 17// 無関係なクラス 18struct Other {}; 19 20 21template <typename TypeList> 22std::shared_ptr<B> Create(const std::type_info* type) 23{ 24 std::shared_ptr<B> result = nullptr; 25 mpl::for_each<TypeList>([&](auto& T) { 26 if (!result && typeid(T) == *type) { 27 result = std::make_shared<std::decay_t<decltype(T)>>(); 28 } 29 }); 30 return result; 31} 32 33int main() 34{ 35 auto* type = &typeid(X); 36 std::shared_ptr<B> px = Create<DrivedB>(type); 37 px->f(); // shared_ptr<X> 38 39 type = &typeid(Y); 40 std::shared_ptr<B> py = Create<DrivedB>(type); 41 py->f(); // shared_ptr<Y> 42 43 type = &typeid(Other); 44 std::shared_ptr<B> po = Create<DrivedB>(type); 45 // OtherクラスはDrivedBリストに含まれないためnullptrを返す 46 assert(po == nullptr); 47}

投稿2016/05/24 10:01

yohhoy

総合スコア6191

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

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

0

こういうことでしょうか。

C++

1template <typename TClass> 2std::shared_ptr<SuperClass> Create() 3{ 4 return std::shared_ptr<SuperClass>(new TClass); 5} 6 7 8int main() 9{ 10 // SubClassAとSubClassBはSuperClassの派生クラス 11 auto pa = Create<SubClassA>(); 12 auto pb = Create<SubClassB>(); 13 14 return 0; 15}

テンプレート引数は<>で括って渡せば良くて、関数の引数は不要です。

投稿2016/05/24 08:52

catsforepaw

総合スコア5938

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

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

0

こんにちは。

typeでTClassの型を動的に切り替えたいと考えています。

動的ということは、typeはSuperClassのポインタか参照でしょうか? もし、YESならyohhoyさんも指摘されているように、無理です。基底クラスのポインタが指すインスタンスの型をコンパイラは把握できませんので、TClassを型推論することは不可能なのです。
しかし、もし、typeがTClassのポインタか参照ならば可能です。普通に型推論できます。

あ、しかし、std::shared_ptr<TClass>std::shared_ptr<SuperClass>へ変換することはできない筈です。
TClassSuperClass間に派生関係があっても、std::shared_ptr<TClass>std::shared_ptr<SuperClass>の間には派生関係がありませんから。
派生関係があると言うことは、下記イメージの定義が存在するということです。

class shared_ptr<TClass> : public shard_ptr<SuperClass> { };

本当にやりたいことを整理された方が良いと思います。

投稿2016/05/24 08:06

Chironian

総合スコア23272

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

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

0

ベストアンサー

例えば、次のようなテンプレート関数があるとします。

C++

1template <typename X> 2X max(X var1 , X var2){ 3 if(var1 > var2) return var1; 4 else return var2; 5}

このテンプレート関数を呼び出すコードは、以下のようになります。

C++

1max<double>(2.718, 3.14);

見慣れない表記があるかもしれません。これは、テンプレートの型を省略しない書き方です。

要するに、テンプレートを呼び出すときに、必要となる型を省略せずに書けばいいと思うのです。
質問の意図と違っていたらごめんなさい。

投稿2016/05/24 07:30

majiponi

総合スコア1720

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

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

hoge_beginner

2016/05/24 09:26

回答ありがとうございます。 テンプレートの型を呼び出し側で指定する記述があったんですね。 typeでswitch,caseを行いcreate関数を呼ぶときに型指定をすることで期待した処理が実現できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問