ตัวดำเนินการที่คลุมเครือใน 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, เสียงดังกราวและ ICC แต่เมื่อรวบรวมกับ GCC (ลำต้น) จะให้ ambigous ข้อผิดพลาดสำหรับบรรทัดoperator<< os << elem << " "และแม้กระทั่งข้อผิดพลาดนี้จะปรากฏเฉพาะเมื่อรวบรวมกับธงหรือ-std=c++17-std=c++2a

ข้อผิดพลาดที่ดูเหมือนว่าเหมาะสมสำหรับstd::stringเนื่องจากคอมไพเลอร์ตรวจพบฟังก์ชั่นที่มีอยู่ที่แม่แบบสำหรับทั่วโลกoperator<<ที่รับกระแส output และbasic_string<CharT, Traits, Allocator>มีประเภทเป็นค่าเริ่มต้นให้Allocatorstd::allocator

คำถามของฉันจะเป็นสาเหตุที่รวบรวมและทำงานร่วมกับ 3 คอมไพเลอร์อื่น ๆ จากความเข้าใจของฉันอย่างน้อยก็ใช้การใช้ไลบรารี่มาตรฐานเดียวกันบน 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>')

และผู้สมัครทั้งสอง

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<<ที่รับกระแส output และbasic_string<CharT, Traits, Allocator>มีประเภทเป็นค่าเริ่มต้นให้Allocatorstd::allocator

ความสามารถนี้เพื่อให้ตรงกับพารามิเตอร์เช่นC<T, A>ชนิดเหมือนbasic_string<CharT, Traits, Allocator=std::allocator<CharT>>เป็นของใหม่ใน C ++ 17 มันมาจากP0522 ก่อนหน้ากระดาษนั้นผู้ให้บริการของคุณจะไม่ถูกพิจารณาว่าเป็นผู้สมัคร

อย่างไรก็ตามเสียงดังกราวตั้งใจเลือกที่จะไม่ใช้คุณสมบัตินี้โดยปริยาย จากสถานะของพวกเขา :

แม้จะเป็นวิธีแก้ไขปัญหารายงานข้อบกพร่องคุณลักษณะนี้จะถูกปิดใช้งานตามค่าเริ่มต้นในทุกภาษาและสามารถเปิดใช้งานอย่างชัดเจนด้วยการตั้งค่าสถานะ-frelaxed-template-template-argsใน Clang 4 เป็นต้นไป การเปลี่ยนแปลงมาตรฐานขาดการเปลี่ยนแปลงที่สอดคล้องกันสำหรับการสั่งซื้อบางส่วนของเทมเพลตส่งผลให้เกิดข้อผิดพลาดในความคลุมเครือสำหรับรหัสที่สมเหตุสมผลและถูกต้องก่อนหน้านี้ ปัญหานี้คาดว่าจะได้รับการแก้ไขในไม่ช้า

คุณสามารถเห็นได้ว่าเมื่อคุณเพิ่มการตั้งค่าสถานะนั้นรหัสของคุณจะคลุมเครือในเสียงดังกราวเช่นกัน ตัวอย่างของคุณเป็นรหัสที่สมเหตุสมผลและถูกต้องก่อนหน้านี้ซึ่งเสียงดังกราวกำลังป้องกันที่นี่ ตัวอย่างที่คล้ายกันที่ฉันเคยเห็น:

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>> เคยเป็นโอเค (ใช้รุ่นไบนารี) แต่ตอนนี้กลายเป็นคลุมเครือ (ระหว่างรุ่น unary และรุ่นไบนารี)

MSVC อาจเป็นตัวเลือกเดียวกัน แต่ฉันไม่รู้ คำตอบที่ถูกต้องตามมาตรฐานคือการโทรนั้นไม่ชัดเจน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.