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

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

ただいまの
回答率

89.20%

結果が通常のメソッドと演算子のオーバーロードとで違ってしまう。

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 231

diode

score 19

質問内容

現在私は可変長引数テンプレートを使い
すべて型が同じ可変長引数から入力された
値をすべて表示するというプログラムを作成しています。

そこで可変長引数を全てstd::coutで出力するprintメソッドと
そのメソッドと全く同じ実装のoperator<<を持つ構造体Aを作成して動かしてみました。
結果はprintメソッドの方は思った通りの動きをしました。
しかしoperator<<の方は可変長引数の最初だけ表示されて残りの引数の内容は
表示されませんでした。

コンパイルはエラーもwaningも吐かずに成功しますが結果がおかしいです。

どうすればoperator<<の方でもすべての値を表示させられるのか教えてください。
どうかよろしくお願いします。

下記がコードです。

#include <iostream>

template<typename TYPE>
struct A{
    template<typename ...ARGS>
    void print(ARGS... args){
        for(const TYPE& itr:{args...}){
            std::cout << itr << ",";
        }
        std::cout << std::endl;
    }

    template<typename ...ARGS>
    A& operator<<(ARGS... args){
        for(const TYPE& itr:{args...}){
            std::cout << itr << ",";
        }
        std::cout << std::endl;
        return *this;
    }
};

int main(){

    A<int> a;
    a.print(1, 2, 3, 4, 5);
    a << 1,2,3,4,5;

    return 0;
} 

結果

1,2,3,4,5, 
1,            ←引数の最初の数字しか表示されない。

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

OS:LinuxMint18.3 Cinammon
コンパイラ:g++ 7.4.0

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

オペランドの数を変更するような形でのオーバーロードは出来ない旨が仕様に明記されています。

It is not possible to change the precedence, grouping, or number of operands of operators.

結果的に二項演算と解釈可能なようにテンプレートが展開されたときに限っては機能するようですが、三項以上に解釈させることはできません。


二項演算子としてのカンマは左側の評価値を捨てるという意味です。 整数などのプリミティブな型同士の演算の意味を変えることは出来ないので、これをオーバーロードすることも出来ません。


あえて、あくまでもあえて見かけだけそれっぽくするということであればこのように書けなくもないですが、錯覚でそれっぽく見えているというだけなので、他の演算子との組み合わせで簡単に破綻するでしょうね。 基本的には無理と思った方がよいと思います。

#include <iostream>

template<typename TYPE>
struct A{
  template<typename ...ARGS>
  void print(ARGS... args){
    for(const TYPE& itr:{args...}){
      std::cout << itr << ",";
    }
    std::cout << std::endl;
  }

  template<class T>
  A& operator<<(T x){
    std::cout << x << ",";
    return *this;
  }

  template<class T>
  A& operator,(T x) {
    std::cout << x << ",";
    return *this;
  }

};

int main(){
  A<int> a;
  a.print(1, 2, 3, 4, 5);
  a << 1,2,3,4,5;

  return 0;
} 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/01 12:38

    SaitoAtsushiさん

    文献のURLとコードを載せていただきありがとうございます。
    otnさんとChironianさんと貴方様のご回答を見る限り
    operatorで複数の右被演算項を
    扱おうとすること自体が邪道なのかなと感じました。
    ご回答誠にありがとうございました。

    キャンセル

0

演算子の優先度で、<<より,が低いので、冗長に括弧を付けると、

( a << 1 ), 2, 3, 4, 5;


ということです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/01 08:42

    otnさん
    ご回答ありがとうございます。

    優先順位の問題なのなら()で優先順位を上げてみようと思い
    a << (1,2,3,4,5);
    と書いたら(1,2,3,4,5)の部分がパラメータパックと認識されなかったようで
    出力が5のみ表示されてしまいました。
    そもそもoperatorで可変長引数テンプレートを取り扱う方法は存在しないのでしょうか。

    キャンセル

  • 2020/02/01 09:47

    可変長というか、複数の右被演算項を扱う方法は無さそうな気がしますが、よくわかりません。

    キャンセル

0

こんにちは。

演算子オーバーロードで引数の数を元の数から変更することはできなかったはずです。
<<は2項演算子なので、左に1つ右に1つしかパラメータを書けません。
関数呼び出し形式を使って無理やり書いたら、clangは「operator<<は2項演算子なのに6つ指定している」というエラーになりました。

// 質問文そのままなので略

int main(){

    A<int> a;
    a.print(1, 2, 3, 4, 5);
//  a << 1,2,3,4,5;
    a.operator<<(1,2,3,4,5);

    return 0;
} 
prog.cc:14:8: error: overloaded 'operator<<' must be a binary operator (has 6 parameters)
    A& operator<<(ARGS... args){
       ^
prog.cc:28:7: note: in instantiation of function template specialization 'A<int>::operator<<<int, int, int, int, int>' requested here
    a.operator<<(1,2,3,4,5);
      ^
prog.cc:28:7: error: no matching member function for call to 'operator<<'
    a.operator<<(1,2,3,4,5);
    ~~^~~~~~~~~~
prog.cc:14:8: note: candidate template ignored: substitution failure [with ARGS = <int, int, int, int, int>]
    A& operator<<(ARGS... args){
       ^
2 errors generated.


wandbox

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/01 12:26

    Chironianさん
    ご回答ありがとうございます。

    clangでは動かないんですね...
    環境に依存するのなら
    使わないほうがいいやり方みたいですね。
    勉強になりました。

    キャンセル

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

  • ただいまの回答率 89.20%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる