C++コンパイラ
  GCCとClangからの
メッセージをお読みください
お詫びとおことわり
●   うっかり自宅のclangにアクセスできなくして
    しまったので、一部のサンプルコード(のエ
    ラーメッセージ)を掲載できなくなってしまい
    ました。
●   なので実感のつかみにくいかもしれませんがご
    了承ください。
GCCのエラーといえば
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void
                           std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’:
                           prog.cpp:6: instantiated from here
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4783: error: no
                           match for ‘operator-’ in ‘__last - __first’
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void
                           std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with
                           _RandomAccessIterator = std::_List_iterator<int>]’:
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated
#include <list>            from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’
                           prog.cpp:6: instantiated from here
#include <algorithm>       /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1827: error: no
                           match for ‘operator-’ in ‘__last - __first’
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1829: error: no
                           match for ‘operator+’ in ‘__first + 16’
int main() {               /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1830: error: no
                           match for ‘operator+’ in ‘__first + 16’
    std::list<int> l;      /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void
                           std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with
                           _RandomAccessIterator = std::_List_iterator<int>]’:
    std::sort(l.begin(),   /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1833: instantiated
                           from ‘void std::__final_insertion_sort(_RandomAccessIterator,
              l.end());    _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated
}                          from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’
                           prog.cpp:6: instantiated from here
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1753: error: no
                           match for ‘operator+’ in ‘__first + 1’
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1833: instantiated
                           from ‘void std::__final_insertion_sort(_RandomAccessIterator,
                           _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated
                           from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’
                           prog.cpp:6: instantiated from here
                           /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1759: error: no
                           match for ‘operator+’ in ‘__i + 1’

 !!!非常に明解で分かりやすい!!!
熟練の暗号解読班の定石手段
●   エラーメッセージから “instantiated from here”
    を探す
●   そこからエラーメッセージを逆に辿りながら、
    実体化された型や関数呼び出しをドキュメント
    と照合する
    ●   テンプレート引数は要件を満たしているか
    ●   実体化されたテンプレートの定義は意図したものか
熟練の暗号解読班の定石手段
●   boost::mpl::eval_if<boost::mpl::apply<boost
    ::remove_reference<boost::mpl::placeholders
    ::……
    ●   perl -ple 's/(?:w+::)*//g'
●   boost::fusion::vector<hoge, fuga, piyo,
    void_, void_, void_, void_, void_, void_,
    void_, ……
    ●   perl -ple 's/,void_//g;'
●   STLfilt
一方新兵はClangを使った
●   ヴィジュアルで位置を指摘してくれる!
        /usr/include/c++/4.3/bits/stl_algo.h:4784:22: error: invalid operands to binary
        expression ('std::_List_iterator<int>' and 'std::_List_iterator<int>')
                                        std::__lg(__last - __first) * 2);
                                                  ~~~~~~ ^ ~~~~~~~


●   マクロ展開後のコードのエラーならそれも追っ
    てくれる! for FOO(1); 'f'
          /tmp/webcompile/_20978_0.cc:6:5: error: no matching function
              call to

                                ^~~
    ●   void f() {}         /tmp/webcompile/_20978_0.cc:2:13: note: instantiated from:
        #define FOO BAR     #define FOO BAR
                                        ^
        #define BAR f
                            /tmp/webcompile/_20978_0.cc:3:13: note: instantiated from:
                            #define BAR f
        int main() {                    ^
            FOO(1);         /tmp/webcompile/_20978_0.cc:1:6: note: candidate function not
        }                   viable: requires 0 arguments, but 1 was provided
                            void f() {}
                                 ^
                            1 error generated.
                                               Clang大勝利!!!
ところが
namespace ns {
    struct z {};
    template<typename T> struct s {};

    template<typename T>
    auto f(s<T> x) -> decltype(f(T())) {
        return f(T());
    }

    template<typename T>
    struct a { static_assert(sizeof(T) && false, "failed"); };

    template<typename T = int>
    auto f(z x) -> decltype(a<T>(), 1) {
        return 0;
    }

    s<s<s<z> > > three;
}

int main() {          これを現行のClangとGCCでコンパイルすると
    f(ns::three);
}                         f(ns::three); の関数呼びだしを解決できなかった
                      という旨のメッセージを吐く
ところが
●   先のコードは、再帰的な実体化を試みた末auto f(z)->
    decltype(a<T>, 0)の実体化に失敗するのが原因
    ●   f(ns::three)の呼び出し解決するためにauto f(s<s<z> >)を実体化しよ
        うとする。
    ●   戻り値の型を求めるためにf(T())の呼び出し解決をしようとする
        –   その呼び出しを解決するためにf(s<z>)を(ry
            ●   その解決のためにf(z)を解決しようとして、失敗する

        –   f(T())の呼び出し解決に失敗する
    ●   f(T())の(ry
    ●   f(ns::three)の呼び出し解決に失敗する
    ●   f(ns::three)の呼び出しがエラーとなる
ところが
●   先のコードは、再帰的な実体化を試みた末auto f(z)->
    decltype(a<T>, 0)の実体化に失敗するのが原因
    ●   f(ns::three)の呼び出し解決するためにauto f(s<s<z> >)を実体化しよ
        うとする。
    ●   戻り値の型を求めるためにf(T())の呼び出し解決をしようとする
        –   その呼び出しを解決するためにf(s<z>)を(ry
            ●   その解決のためにf(z)を解決しようとして、失敗する

        –   f(T())の呼び出し解決に失敗する
    ●   f(T())の(ry
    ●   f(ns::three)の呼び出し解決に失敗する
    ●   f(ns::three)の呼び出しがエラーとなる
老兵再び
●   Clangには呼び出し解決に失敗した場合、各呼び
    出し候補について、その候補が選ばれなかった
    理由を表示する機能がある。
●   GCC4.7にも同様の機能が付いたが、こちらはあ
    る候補の選択されなかった理由が「関数の呼び
    出し解決失敗」である場合、その呼び出しの候
    補と失敗理由についても再帰的に表示してくれ
    る
      GCC(>=4.7)大勝利!!!
まとめ
●   両方でコンパイルできるようにコードを書い
    て、適切に使い分けましょう
問題
●   ドキュメントがない部分(内部実装など)を通る
    と、どの実体化でおかしくなったのか判別する
    ことが困難
    ●   See: PStade.Oven

C++コンパイラ GCCとClangからのメッセージをお読みください

  • 1.
  • 2.
    お詫びとおことわり ● うっかり自宅のclangにアクセスできなくして しまったので、一部のサンプルコード(のエ ラーメッセージ)を掲載できなくなってしまい ました。 ● なので実感のつかみにくいかもしれませんがご 了承ください。
  • 3.
    GCCのエラーといえば /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’: prog.cpp:6: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4783: error: no match for ‘operator-’ in ‘__last - __first’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’: /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated #include <list> from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’ prog.cpp:6: instantiated from here #include <algorithm> /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1827: error: no match for ‘operator-’ in ‘__last - __first’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1829: error: no match for ‘operator+’ in ‘__first + 16’ int main() { /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1830: error: no match for ‘operator+’ in ‘__first + 16’ std::list<int> l; /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h: In function ‘void std::__insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’: std::sort(l.begin(), /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1833: instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, l.end()); _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated } from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’ prog.cpp:6: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1753: error: no match for ‘operator+’ in ‘__first + 1’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1833: instantiated from ‘void std::__final_insertion_sort(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = std::_List_iterator<int>]’ /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:4785: instantiated from ‘void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]’ prog.cpp:6: instantiated from here /usr/lib/gcc/i686-pc-linux-gnu/4.3.4/include/g++-v4/bits/stl_algo.h:1759: error: no match for ‘operator+’ in ‘__i + 1’ !!!非常に明解で分かりやすい!!!
  • 4.
    熟練の暗号解読班の定石手段 ● エラーメッセージから “instantiated from here” を探す ● そこからエラーメッセージを逆に辿りながら、 実体化された型や関数呼び出しをドキュメント と照合する ● テンプレート引数は要件を満たしているか ● 実体化されたテンプレートの定義は意図したものか
  • 5.
    熟練の暗号解読班の定石手段 ● boost::mpl::eval_if<boost::mpl::apply<boost ::remove_reference<boost::mpl::placeholders ::…… ● perl -ple 's/(?:w+::)*//g' ● boost::fusion::vector<hoge, fuga, piyo, void_, void_, void_, void_, void_, void_, void_, …… ● perl -ple 's/,void_//g;' ● STLfilt
  • 6.
    一方新兵はClangを使った ● ヴィジュアルで位置を指摘してくれる! /usr/include/c++/4.3/bits/stl_algo.h:4784:22: error: invalid operands to binary expression ('std::_List_iterator<int>' and 'std::_List_iterator<int>') std::__lg(__last - __first) * 2); ~~~~~~ ^ ~~~~~~~ ● マクロ展開後のコードのエラーならそれも追っ てくれる! for FOO(1); 'f' /tmp/webcompile/_20978_0.cc:6:5: error: no matching function call to ^~~ ● void f() {} /tmp/webcompile/_20978_0.cc:2:13: note: instantiated from: #define FOO BAR #define FOO BAR ^ #define BAR f /tmp/webcompile/_20978_0.cc:3:13: note: instantiated from: #define BAR f int main() { ^ FOO(1); /tmp/webcompile/_20978_0.cc:1:6: note: candidate function not } viable: requires 0 arguments, but 1 was provided void f() {} ^ 1 error generated. Clang大勝利!!!
  • 7.
    ところが namespace ns { struct z {}; template<typename T> struct s {}; template<typename T> auto f(s<T> x) -> decltype(f(T())) { return f(T()); } template<typename T> struct a { static_assert(sizeof(T) && false, "failed"); }; template<typename T = int> auto f(z x) -> decltype(a<T>(), 1) { return 0; } s<s<s<z> > > three; } int main() { これを現行のClangとGCCでコンパイルすると f(ns::three); } f(ns::three); の関数呼びだしを解決できなかった という旨のメッセージを吐く
  • 8.
    ところが ● 先のコードは、再帰的な実体化を試みた末auto f(z)-> decltype(a<T>, 0)の実体化に失敗するのが原因 ● f(ns::three)の呼び出し解決するためにauto f(s<s<z> >)を実体化しよ うとする。 ● 戻り値の型を求めるためにf(T())の呼び出し解決をしようとする – その呼び出しを解決するためにf(s<z>)を(ry ● その解決のためにf(z)を解決しようとして、失敗する – f(T())の呼び出し解決に失敗する ● f(T())の(ry ● f(ns::three)の呼び出し解決に失敗する ● f(ns::three)の呼び出しがエラーとなる
  • 9.
    ところが ● 先のコードは、再帰的な実体化を試みた末auto f(z)-> decltype(a<T>, 0)の実体化に失敗するのが原因 ● f(ns::three)の呼び出し解決するためにauto f(s<s<z> >)を実体化しよ うとする。 ● 戻り値の型を求めるためにf(T())の呼び出し解決をしようとする – その呼び出しを解決するためにf(s<z>)を(ry ● その解決のためにf(z)を解決しようとして、失敗する – f(T())の呼び出し解決に失敗する ● f(T())の(ry ● f(ns::three)の呼び出し解決に失敗する ● f(ns::three)の呼び出しがエラーとなる
  • 10.
    老兵再び ● Clangには呼び出し解決に失敗した場合、各呼び 出し候補について、その候補が選ばれなかった 理由を表示する機能がある。 ● GCC4.7にも同様の機能が付いたが、こちらはあ る候補の選択されなかった理由が「関数の呼び 出し解決失敗」である場合、その呼び出しの候 補と失敗理由についても再帰的に表示してくれ る GCC(>=4.7)大勝利!!!
  • 11.
    まとめ ● 両方でコンパイルできるようにコードを書い て、適切に使い分けましょう
  • 12.
    問題 ● ドキュメントがない部分(内部実装など)を通る と、どの実体化でおかしくなったのか判別する ことが困難 ● See: PStade.Oven