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

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

詳細はこちら
C++

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

Q&A

解決済

3回答

1649閲覧

C++で配列をテンプレートで扱って、operator<<をオーバーロードしたい

pandanoir

総合スコア72

C++

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

0グッド

1クリップ

投稿2019/10/09 07:22

編集2019/10/09 07:32

競プロにおいて、

cpp

1int A[3] = {1, 2, 3}; 2cout << A << "\n";

のようなことをしたくてoperator<<をオーバーロードしようとしたのですが、つまづいてしまいました。

http://koyumeishi.hatenablog.com/entry/2016/02/01/152426

このサイトで、vector<T>でのオーバーロードがあったので、これを参考に自分で書いてみたのですが、うまくいきません。

cpp

1template<typename T, size_t SIZE>ostream& operator<<(ostream& os, T(&arr)[SIZE]){ 2 os<<"{"; 3 for(int i=0;i<SIZE;++i) 4 os<<(i?", ":"")<<arr[i]; 5 os<<"}"; 6 return os; 7}

これだと、const char[SIZE]も含まれてしまい、「os<<"{";がambiguousだよ」と怒られます(それはそう)。オーバーロードで実装するとしたら、どうするのがいいのでしょうか?

追記

単にdebug_arr(T(&arr)[SIZE])という関数として実装しようとすると、二次配列のときにうまくデバッグができないので、オーバーロードでの実装を知りたいです。

cpp

1template<typename T, size_t SIZE>void debug_arr(2T(&arr)[SIZE]){ 2 cout<<"{"; 3 for(int i=0;i<SIZE;++i) 4 cout<<(i?", ":"")<<arr[i]; 5 cout<<"}"; 6} 7int A[2][3] = { 8 {1,2,3}, 9 {4,5,6}, 10}; 11debug_arr(A); // {配列のアドレス,配列のアドレス}という出力がされる

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

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

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

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

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

guest

回答3

0

オーバーロードで実装するとしたら、どうするのがいいのでしょうか?

多少強引ですが、競プロ目的であれば「char配列だけ除外」するのはいかがでしょう。(char配列はそうそう使わないだろうという仮定)

c++

1#include <iostream> 2#include <type_traits> 3using namespace std; 4 5template<typename T, size_t SIZE> 6enable_if_t<!is_same_v<char, remove_cv_t<T>>, ostream>& 7operator<<(ostream& os, T (&arr)[SIZE]) 8{ 9 os<<"{"; 10 for(size_t i=0;i<SIZE;++i) 11 os<<(i?", ":"")<<arr[i]; 12 os<<"}"; 13 return os; 14}

投稿2019/10/09 15:28

yohhoy

総合スコア6191

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

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

yohhoy

2019/10/09 15:32

Chironianさん回答と同じ内容を、違う実装方法で書いてるだけでした。SFINAEを発火させる場所が違うだけですね。
guest

0

ベストアンサー

こんにちは。

クラス・テンプレートなら部分特殊化するところ(Tからconstを除いた型がchar型でない)ですね。
関数テンプレートはオーバーロードにて部分特殊化できます。

C++

1#include<iostream> 2#include<type_traits> 3 4template<typename T, size_t SIZE, std::enable_if_t<!std::is_same_v<std::remove_cv_t<T>, char>, std::nullptr_t> = nullptr> 5std::ostream& operator<<(std::ostream& os, T(&arr)[SIZE]) 6{ 7 os<<"{"; 8 for(std::size_t i=0;i<SIZE;++i) 9 os<<(i?", ":"")<<arr[i]; 10 os<<"}"; 11 return os; 12} 13 14int main() 15{ 16 int A[3] = {1, 2, 3}; 17 std::cout << A << "\n"; 18}

wandbox

微妙に手抜きしているので C++17 が必須です。*_t*_vをやめればC++11でもコンパイルできます。
でも、typenameを書かないといけなくなります。

投稿2019/10/09 12:58

Chironian

総合スコア23272

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

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

0

C++20で配列からstd::arrayへの変換ができるらしいので
そっち使うのも将来的にはありじゃないかなと

c++

1#include <array> 2#include <iostream> 3 4template <typename T, size_t SIZE> 5std::ostream& operator<<(std::ostream& os, const std::array<T, SIZE> &array) 6{ 7 bool head = true; 8 for(const auto& it : array){ 9 os << (!head?", ":"") << it; 10 head = false; 11 } 12 return os; 13} 14 15int main() 16{ 17 int a[] = {1,2,3,4}; 18 auto aa = std::to_array(a); 19 char b[] = "abcd\0efg"; 20 std::cout << aa << "\n"; 21 std::cout << b << "\n"; 22 std::cout << std::to_array(b); 23}

投稿2019/10/09 23:46

asm

総合スコア15149

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問