gccのあいまいな演算子


13

stlコンテナーの一部を印刷するための関数テンプレートを作成しました

#include <iostream>
#include <vector>
#include <string>

template <template <typename, typename> class C, typename T, typename A>
std::ostream& operator<<(std::ostream& os, const C<T, A>& container)
{ 
    for (auto& elem : container) 
    { 
        os << elem << " "; 
    } 

    return os; 
}

int main()
{
    std::vector<std::string> v { "One", "Two", "Three" };

    std::cout << v << std::endl;

    return 0;
}

これは、MSVC、Clang、およびICCでコンパイルおよび期待どおりに機能しますが、GCC(trunk)でコンパイルするとoperator<<、行にあいまいなエラーが発生しますos << elem << " "。また、このエラーはフラグ-std=c++17またはを使用してコンパイルした場合にのみ表示されます-std=c++2a

エラーがために、合理的なようだstd::stringコンパイラはグローバルのために、既存の関数テンプレートを検出するので、operator<<出力ストリームと受け入れbasic_string<CharT, Traits, Allocator>て、Allocator型がにデフォルト設定されているがstd::allocator

私の質問はなぜそれが他の3つのコンパイラでコンパイルおよび動作するのか、私の理解から、少なくともClangはLinuxでgccと同じ標準ライブラリ実装を使用しているため、 operator<<

報告されたエラーは

error: ambiguous overload for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'const std::__cxx11::basic_string<char>')

そして2人の候補者

note: candidate: 'std::ostream& operator<<(std::ostream&, const C<T, A>&) [with C = std::__cxx11::basic_string; T = char; A = std::char_traits<char>; std::ostream = std::basic_ostream<char>]'

note: candidate: 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&, const std::__cxx11::basic_string<_CharT, _Traits, _Allocator>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]'

GCC、Clang、ICCのコンパイラー引数

-std=c++2a -O3 -Wall -Wextra -Wpedantic -Werror

MSVC用

/std:c++latest /O2 /W3

必須のgodboltリンク:https ://godbolt.org/z/R_aSKR

回答:


8

エラーがために、合理的なようだstd::stringコンパイラはグローバルのために、既存の関数テンプレートを検出するので、operator<<出力ストリームと受け入れbasic_string<CharT, Traits, Allocator>て、Allocator型がにデフォルト設定されているがstd::allocator

パラメータをlikeのようなC<T, A>型に一致させるこの機能basic_string<CharT, Traits, Allocator=std::allocator<CharT>>はC ++ 17の新機能であり、P0522に由来しています。その論文の前は、あなたのオペレーターは候補者とは見なされませんでした。

ただし、clangは意図的にこの機能をデフォルトで実装しないことを選択しています。彼らのステータスから:

欠陥レポートの解決策であるにもかかわらず、この機能はすべての言語バージョンでデフォルトで無効になっており-frelaxed-template-template-args、Clang 4以降のフラグで明示的に有効にすることができます。標準への変更には、テンプレートの部分的な順序付けに対応する変更が欠けているため、妥当で以前は有効だったコードのあいまいなエラーが発生します。この問題はすぐに修正される予定です。

そのフラグを追加すると、コードがclangでもあいまいになることがわかります。あなたの例は、clangがここから保護している、合理的で以前は有効だった種類のコードです。私が見た同様の種類の例:

template <class T> struct some_trait;

template <template <class> class C, class A>
struct some_trait<C<A>> { /* ... */ };

template <template <class> class C, class A, class B>
struct some_trait<C<A, B>> { /* ... */ };

some_trait<vector<int>> 以前は(バイナリバージョンを使用して)大丈夫でしたが、(単項バージョンとバイナリバージョンの間で)あいまいになりました。

MSVCも同じ選択をする可能性がありますが、わかりません。標準ごとの正解は、呼び出しがあいまいであることです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.