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

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

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

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

Q&A

解決済

4回答

1421閲覧

sort()で使うpair型の比較関数をテンプレート化するとエラーが出るので解消したい

moko3

総合スコア3

C++

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

0グッド

1クリップ

投稿2023/03/09 13:12

質問

Q:エラーを解消する方法を知りたい

実現したいこと

比較関数のbool comp1(pi a, pi b) {}をtemplate化してsort()で使いたい

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

イメージ説明

sort +4 個のオーバーロード オーバーロードされた関数 "sort" のインスタンスが引数リストと一致しませんC/C++(304) q2.cpp(28, 3): 引数の型: (__gnu_cxx::__normal_iterator<pi *, std::vector<pi, std::allocator<pi>>>, __gnu_cxx::__normal_iterator<pi *, std::vector<pi, std::allocator<pi>>>, <unknown-type>)

該当のソースコード

C++17

C++

1#include <bits/stdc++.h> 2using namespace std; 3 4using pi = pair<int, int>; 5 6// template無し 7bool comp1(pi a, pi b) { return a.first != b.first ? a.first < b.first : a.second < b.second; } 8 9// template化したいがsort()関数で使うとエラーになる 10template<class T, class U> 11bool comp2(pair<T, U> a, pair<T, U> b) { 12 return a.first != b.first ? a.first < b.first : a.second < b.second; 13} 14 15void output(vector<pi> v) { 16 for (auto e : v) cout << e.first << " " << e.second << "/n"; 17} 18 19void solve() { 20 // input 21 vector<pi> v {{1, 3}, {2, 2}, {3, 1}, {9, 7}, {8, 8}, {7, 9}}; 22 23 // sort1 24 sort(v.begin(), v.end(), comp1); 25 output(v); 26 27 // sort2 28 // ↓※このsort()でエラーとなるが原因が分からない 29 sort(v.begin(), v.end(), comp2); 30 output(v); 31} 32 33int main() { (solve()); } 34

試したこと

・comp1のように比較関数の引数の型を明示するとエラーは出なかった
・comp2を使ったsort2をコメントアウトしてコンパイルすると通るのでtemplate化したcomp2は間違っていない気がする
・sort2のsort()の引数の指定の仕方がtemplate化したことによって違っているとエラーから推測出来るのですが
どのように指定したらエラーが解消するのか分からない

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

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

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

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

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

guest

回答4

0

ベストアンサー

関数だとstd::sortのtemplate _Compareが関数ポインタになるわけで、 引数のためにsort2関数をインスタンス化する必要があるわけだけど、このsortを呼び出す時点では、sort2に与えるT,Uが分からなくて詰むんじゃない?

sort2<int,int>とかで手動でテンプレートを指定しても動くけど、functor classにしとけばインスタンス化をsortの_Compareの呼び出し時点まで引き延ばせるので、T、Uが自動解決できるのでは。

cpp

1struct sort2{ 2template<class T, class U> 3bool operator()(pair<T, U> a, pair<T, U> b) {return a.first != b.first ? a.first < b.first : a.second < b.second;} 4};

投稿2023/03/09 14:56

matukeso

総合スコア1590

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

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

moko3

2023/03/09 15:32

回答ありがとうございます。
moko3

2023/03/09 15:47

「functor class」(ファンクタ)という概念を知らなかったので勉強になりました。 引数で型を指定して渡すのはテンプレート化する意味が無いような気がするので struct{}にしておいた方が汎用性があると思いました。
guest

0

解決方法は出てきているようなので背景にある理屈を少し補足しておきます。

テンプレートの詳細は複雑なのですが大雑把には

  • 関数テンプレートは関数ではない。 クラステンプレートはクラスではない。
  • 関数テンプレートにテンプレート引数を当てはめたものは関数、クラステンプレートにテンプレート引数を当てはめたものはクラス
  • テンプレートはそれが必要とされるところで暗黙に実体化される (明示的に実体化することもできる)
  • 状況によってはテンプレート引数は自動的に推論してくれることもある

たとえば

cpp

1template<class T> 2T foo(T x) { 3 return x; 4} 5 6int main(void) { 7 foo(1); 8}

というようなコードがあれば 1int であることを元にして Tint であることが推論されて foo<int>(1); というように呼び出したのと同じであることになります。 つまり実引数から仮引数が推論されました。 テンプレート実引数を省略したときにテンプレート実引数が無いのではなく、推論によって埋められて具体的な型になって処理されているのです。

逆に仮引数から実引数が推論されることもあります。

cpp

1template<class T> 2T foo(T x) { 3 return x; 4} 5 6void bar(int (*)(int)) {} 7 8int main(void) { 9 bar(foo); 10}

では引数を与えるほうも受け取るほうもテンプレートだったらどうなるかというとエラーです。 std::sort も関数テンプレートなので質問の事例はこの場合に当てはまります。

cpp

1template<class T> 2T foo(T x) { 3 return x; 4} 5 6template<class T> 7void bar(T x) {} 8 9int main(void) { 10 // テンプレート引数を埋めるための推論ができないのでエラー 11 bar(foo); 12}

解決方法としては二種類が考えられます。

  • 推論に頼らずにテンプレート引数を与える (lehshell 氏の提案)
  • 推論可能なように変形する (matukeso 氏の提案)

状況によりますが汎用的に使うライブラリとしてまとめることを指向するなら基本的には推論可能な形になっているほうが好ましいでしょう。 (いちいち型を書かずに済むならそのほうがよいので。)

投稿2023/03/12 07:48

SaitoAtsushi

総合スコア5446

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

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

moko3

2023/03/12 11:14

回答ありがとうございます。 >>std::sort も関数テンプレート >>推論可能な形になっているほうが好ましい 丁寧な説明をして頂いてとても勉強になります。
guest

0

C++

1//sort(v.begin(), v.end(), comp2); 2sort(v.begin(), v.end(), comp2<int, int>);

投稿2023/03/09 14:49

lehshell

総合スコア1147

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

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

moko3

2023/03/09 15:32

回答ありがとうございます。
guest

0

C++17まで使ってよければ、std::pair<T1,T2>型はstd::less<>を使って昇順ソート可能です。比較時にはT1T2順に<比較が行われます。

cpp

1#include <functional> // std::less 2 3sort(v.begin(), v.end(), less<>{});

std::less<>の仕組みは matukeso さん回答の通りで、同クラスoperator()がテンプレート化されています。
実際の比較処理は std::pairoperator< が呼び出されます。

投稿2023/03/10 09:10

編集2023/03/10 09:13
yohhoy

総合スコア6191

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

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

moko3

2023/03/10 09:36

回答ありがとうございます。 質問をなるべく簡単にするためにtemplate化でエラーが出ることだけに絞って質問していました。 first昇順,first降順,second昇順,second降順の4種類を何かしらの形でテンプレとしたかったです。 後出しで条件追加のようになってしまいすみません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問