🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

C++

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

Q&A

解決済

1回答

508閲覧

c++:テンプレートテンプレートを関数に渡したい

otyaken

総合スコア9

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

関数

関数(ファンクション・メソッド・サブルーチンとも呼ばれる)は、はプログラムのコードの一部であり、ある特定のタスクを処理するように設計されたものです。

C++

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

0グッド

0クリップ

投稿2019/10/27 05:04

編集2019/10/27 05:13

前提

データを保存しておくクラスSettingを作成し,データを渡す相手クラスによって処理を変更するような処理を実現したいです.

これを実現する例として,静的ポリモーフィズムを利用し,テンプレートクラスTypeを受け取り,それを表示するような基底クラスBaseと派生クラスDerivedを作成しました.

c++

1/** 2 * 静的ポリモーフィズム基底クラス 3 */ 4template<class Type, template<class>class Derived> 5class Base{ 6 public: 7 static void print(Type data){ 8 Derived<Type>::print(data); 9 } 10}; 11 12/** 13 * 静的ポリモーフィズム派生クラス 14 */ 15template<class Type> 16class Derived : Base<Type, Derived>{ 17 public: 18 static void print(Type data){ 19 std::cout << data << std::endl; 20 } 21};

表示するデータはSettingクラスを作成して保存します.
SettingクラスにはデータをBaseクラスに渡して表示するような関数Setting::printを作成しました.

c++

1/** 2 * データを保存しておくクラス 3 */ 4template<class Type> 5class Setting{ 6 public: 7 Type data; 8 9 public: 10 /** 11 * データをBaseクラスに渡して出力する関数 12 */ 13 template<template<class>class Derived> 14 void print(){ 15 Base<Type, Derived>::print(data); 16 } 17};

実装したいこと

このSettingクラスを別の関数に渡し.Setting::print関数を呼び出すようにしたいのですが,コンパイルエラーが発生してしまいました.

c++

1/** 2 * これはNG 3 */ 4template<class Type, template<class>class Derived> 5void NGprint(Setting<Type> &setting){ 6 setting.print<Derived<Type>>(); 7} 8int main(){ 9 /** 10 * Settingクラスの初期化 11 */ 12 Setting<double> setting; 13 setting.data = 1.0; 14 15 NGprint<double, Derived>(setting); 16}

試したこと

これらのクラスを使って,Settingクラスが定義されている関数内からSetting::print関数を呼び出すことができました.

c++

1/** 2 * main関数 3 */ 4int main(){ 5 /** 6 * Settingクラスの初期化 7 */ 8 Setting<double> setting; 9 setting.data = 1.0; 10 11 setting.print<Derived>(); 12}

また,関数を渡すときにTypeをあらかじめ指定すればコンパイルできました.

c++

1template<template<class>class Derived> 2void OKprint(Setting<double> &setting){ 3 setting.print<Derived>(); 4} 5 6void main(){ 7 /** 8 * Settingクラスの初期化 9 */ 10 Setting<double> setting; 11 setting.data = 1.0; 12 13 OKprint<Derived>(setting); 14}

質問内容

どのように修正をすればよいでしょうか.
また,よりよい実装方法をご存じでしたら,ご教授願います.

コード全文

c++

1#include <cstdio> 2#include <iostream> 3 4/** 5 * クラスの前方宣言 6 */ 7template<class Type> 8class Setting; 9 10template<class Type, template<class>class Derived> 11class Base; 12 13template<class Type> 14class Derived; 15 16 17/** 18 * int型を保存しておくクラス 19 */ 20template<class Type> 21class Setting{ 22 public: 23 Type data; 24 25 public: 26 /** 27 * dataを使用するクラス 28 */ 29 template<template<class>class Derived> 30 void print(){ 31 Base<Type, Derived>::print(data); 32 } 33}; 34 35/** 36 * 静的ポリモーフィズム基底クラス 37 */ 38template<class Type, template<class>class Derived> 39class Base{ 40 public: 41 static void print(Type data){ 42 Derived<Type>::print(data); 43 } 44}; 45 46/** 47 * 静的ポリモーフィズム派生クラス 48 */ 49template<class Type> 50class Derived : Base<Type, Derived>{ 51 public: 52 static void print(Type data){ 53 std::cout << data << std::endl; 54 } 55}; 56 57/** 58 * これはNG 59 */ 60template<class Type, template<class>class Derived> 61void NGprint(Setting<Type> &setting){ 62 setting.print<Derived<Type>>(); 63} 64/** 65 * main関数 66 */ 67int main(){ 68 /** 69 * Settingクラスの初期化 70 */ 71 Setting<double> setting; 72 setting.data = 1.0; 73 74 NGprint<double, Derived>(setting); 75}

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

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

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

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

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

guest

回答1

0

ベストアンサー

こんにちは。

これで行けるようです。

C++

1template<class Type, template<class>class Derived> 2void NGprint(Setting<Type> &setting){ 3 setting.template print<Derived>(); 4}

setting::print()はテンプレート・メンバー関数なので template 指定が必要になります。
また、この文脈ではDerived<Type>は実体化されてクラスになっており、テンプレートではないようです。
それをテンプレート・テンプレート・パラメータへ渡すのはダメということと思います。

投稿2019/10/27 06:41

Chironian

総合スコア23272

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

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

otyaken

2019/10/27 07:39 編集

いただいたプログラムで実行することができました.ありがとうございます. まだまだ勉強が足りていないみたいです. 質問なのですが,すべてのテンプレートメンバー関数を呼び出す際にtemplate指定が必要ということなのでしょうか.
SaitoAtsushi

2019/10/27 07:44

関数テンプレート `NGprint` の定義に先んじて `Setting` クラスは宣言されていてメンバ関数 `print` がテンプレートであることは明らかに見えますが、 `Setting` には特殊化が追加される可能性 (そこでは `print` はテンプレートではないかもしれない) もあります。 `NGprint` の定義時点では `setting.print` がテンプレートであるかどうかは判断できません。 なので template キーワードで明示する必要があります。 もし setting がクラステンプレートではないのであればそのような可能性はないのでメンバがテンプレートであることは確定し、 template キーワードで修飾しなくてもテンプレートであることがわかります。 なので `template` キーワードは必要はありません。 "2 phase lookup" でウェブ検索すれば具体的なルールは知ることが出来るはずです。
Chironian

2019/10/27 07:47

私も正確には分かっていないのですが、テンプレート・パラメータに依存するテンプレート・メンバー関数を呼び出す際に必要になると理解しています。 なんとなくコンパイラにとっての「誤解の余地」をなくすための指定だろうと思っています。
otyaken

2019/10/27 07:53

ありがとうございます.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問