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

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

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

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

C++

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

Q&A

2回答

1562閲覧

template関数が呼べない

template

総合スコア0

C

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

C++

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

0グッド

0クリップ

投稿2020/07/19 16:06

編集2020/07/20 02:18

前提・実現したいこと

ヘッダファイルでtemplate関数を作成しました。ヘッダファイルをインクルードしたソースファイルで、作成したtemplate関数を呼び出したいんですがエラーが発生してます。template関数の呼び出しについてのサイトはたくさんありますが解決には至りませんでした、よろしくおねがいします。

発生している問題・エラーメッセージ

no instance of function template "ネームスペース名::クラス名::関数名" matches the argument list and object (the object has type qualifiers that prevent a match)

該当のソースコード

ヘッダファイル namespace A{ class B{ private: Run2(); template <int P, int R> void Run(int U = 0,float T = 0);
ソースファイル namespace A{ class B{ void クラス名::Run2() { //元々Runを実行している関数:エラーなし #define CASE_PP(pp, rr) \ case pp: \ Run<10 * pp + 1, rr>(); \ break; #define CASE_RR(rr) \ case rr: \ switch (something_.pp) { \ CASE_PP(1, rr) \ CASE_PP(2, rr) \ default: { \ std::cerr << "Error1" << std::endl; \ break; \ } \ } \ break; switch (something_.rr) { CASE_RR(1) CASE_RR(2) default: { std::cerr << "Error2" << std::endl; break; } } #undef SWITCH_PP #undef CALL_RUN2_FUNC } Run<10 , 10>(); //Run2とは違う場所で実行したい //これに対して上のエラー template <int P, int R> //実装 void Run(int U,float T){ 省略 }

試したこと

引数リストとオブジェクトが違います、と言われた気がしたのでそもそものヘッダファイルで定義したtemplate関数が間違っている(RとTの型が違うから)のかと考えましたが、ソースファイルでの実行コマンドをコメントアウトするとエラーは消えるため、定義はあっていると思いました。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答2

0

templateの関数やクラスを全て
ヘッダに記載すれば良いことについては
私より先にBearded-Ockhamさんが
仰る通りですが

私の知る限りtemplateの関数やクラスをヘッダと実装で
分ける方法があと2つあります

方法1:明示的実体化を使う

c++

1//func.hpp 2#pragma once 3 4template <int P, int R> 5void Run(int U = 0,float T = 0);

c++

1//func.cpp 2#include <func.hpp> 3#include <iostream> 4 5template <int P, int R> 6void Run(int U,float T){ 7 std::cout << "Runがよびだされました" << std::endl; 8} 9 10template void Run<10,10>(int U,float T);// ← 明示的実体化

c++

1//main.cpp 2#include <iostream> 3#include <func.hpp> 4 5int main(){ 6 7 Run<10,10>(); 8 9 return 0; 10}

上記コードは一応コンパイルは通りますが
明示的実体化部分のテンプレート引数を
呼び出し側(main関数内)のテンプレート引数と合わせないと
コンパイルエラーが発生してしまうので
今回の関数の場合かなり実用的ではないです...

方法2:cppファイルをヘッダからインクルードする

c++

1//func.hpp 2#pragma once 3 4template <int P, int R> 5void Run(int U = 0,float T = 0); 6 7#include"func.cpp"// ← ここからfanc.cppを呼び出す

c++

1//func.cpp 2#include <iostream> 3 4template <int P, int R> 5void Run(int U,float T){ 6 std::cout << "Runがよびだされました" << std::endl; 7}

c++

1//main.cpp 2#include <iostream> 3#include <func.hpp> 4 5int main(){ 6 7 Run<10,10>(); 8 9 return 0; 10}

この方法はfanc.hppの最後の行でfanc.cppを呼び出しているので
実質fanc.cppはヘッダー扱いなのですが
明示的実体化をしなくても良いのでおすすめです。
また今回の場合この方法ではRun関数のテンプレート引数
にどのような値を入れても動くので方法1よりは
遥かに実用的なのではないでしょうか。

ですが個人的にはBearded-Ockhamさんの仰る
ヘッダーに実装も書いてしまうという方法が
最も一般的なのかなと思います。

投稿2020/07/19 23:18

編集2020/07/19 23:23
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

template

2020/07/20 02:22

方法2のmain関数でRunを実行していますが、それをソースファイルのRun実装の後ろにおいてもよいのでしょうか。実装の後に来るようにRun実行を持ってきましたがエラーは改善されませんでした。別の場所でもともとtemplate関数を呼び出していたコードを発見したので追記しましたが、実装前に呼び出しているように思えます。
退会済みユーザー

退会済みユーザー

2020/07/20 07:43 編集

templateさん お返事ありがとうございます。 >ソースファイルのRun実装の後ろにおいてもよいのでしょうか Runの定義直後に実装の記されたファイルを インクルードしても問題ないかと思われます。 > 実装の後に来るようにRun実行を持ってきましたがエラーは改善されませんでした 定義後実装をインクルードする部分で 指定している実装の記載されたファイルのパスは 合っているでしょうか もしかしたらそこが原因かもしれません。
guest

0

template関数は、文字通り、関数のテンプレートです。定義しただけでは実体はなく、使用されていることをコンパイラが見つけた時に、コンパイラが定義から実体を作成します。逆に言えば、使ったときに定義がなければ、実体を生成できずにエラーになります。

なので、Runの実装を呼び出す前に置いてください。template関数の実装が、普通headerに置かれているのは、このためです。

また、Runはメンバー関数(のテンプレート)なので、それだけを呼び出すことはできません。インスタンスを作成して、呼び出す必要があります。例えば

C++

1int main() { 2 A::B b; 3 b.Run<10,10>(); 4}

また、提示のソースだと'Run`はprivateなので、publicにしないと呼べません。

投稿2020/07/19 17:24

編集2020/07/20 03:09
Bearded-Ockham

総合スコア430

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

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

template

2020/07/20 02:13

Run()の実装後に実行をするように順番を変更するということでしょうか。以下のように変更しましたがエラーが改善されませんでした。このtemplate関数を呼び出しているコードがソースファイル内の他の場所で見つかったため、質問に追記しました。この場合switch文を使って実装よりも前に呼び出しているようなのですが、エラーは発生していません。 ``` //ソースファイル #include ヘッダファイル namespace A{ class B{ template <int P, int R> //実装 void Run(int U,float T){ 省略 } int P = 10; int R = 10; Run<P, R>(); ```
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問