Toán tử mơ hồ trong gcc


13

Tôi đã tạo một mẫu hàm để in một số thùng chứa 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;
}

Điều này biên dịch và hoạt động như mong đợi trên MSVC, Clang và ICC, nhưng khi biên dịch với GCC (trung kế), nó sẽ operator<<gây ra lỗi không rõ ràng cho dòng os << elem << " ". Và thậm chí lỗi này chỉ xuất hiện khi biên dịch với cờ -std=c++17hoặc -std=c++2a.

Lỗi có vẻ hợp lý, vì std::string, trình biên dịch phát hiện một mẫu hàm hiện có cho toàn cầu operator<<chấp nhận luồng đầu ra và a basic_string<CharT, Traits, Allocator>, với Allocatorkiểu được mặc định std::allocator.

Câu hỏi của tôi là tại sao nó biên dịch và làm việc với 3 trình biên dịch khác, theo hiểu biết của tôi, Clang ít nhất, sử dụng cùng một triển khai thư viện tiêu chuẩn trên linux như gcc, vì vậy nó có cùng một khuôn mẫu hàm cho operator<<

Lỗi được báo cáo là

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

Và hai ứng cử viên

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>]'

Trình biên dịch đối số cho GCC, Clang và ICC

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

An cho MSVC

/std:c++latest /O2 /W3

Liên kết Godbolt bắt buộc: https://godbolt.org/z/R_aSKR

Câu trả lời:


8

Lỗi có vẻ hợp lý, vì std::string, trình biên dịch phát hiện một mẫu hàm hiện có cho toàn cầu operator<<chấp nhận luồng đầu ra và a basic_string<CharT, Traits, Allocator>, với Allocatorkiểu được mặc định std::allocator.

Khả năng này để khớp một tham số như C<T, A>một kiểu như basic_string<CharT, Traits, Allocator=std::allocator<CharT>>là mới trong C ++ 17, nó đến từ P0522 . Trước bài báo đó, nhà điều hành của bạn sẽ không được coi là một ứng cử viên.

Tuy nhiên, clang cố ý chọn không thực hiện tính năng này theo mặc định. Từ trạng thái của họ :

Mặc dù là độ phân giải của Báo cáo lỗi, tính năng này bị tắt theo mặc định trong tất cả các phiên bản ngôn ngữ và có thể được bật rõ ràng bằng cờ -frelaxed-template-template-argstrong Clang 4 trở đi. Thay đổi đối với tiêu chuẩn thiếu một thay đổi tương ứng đối với thứ tự một phần của mẫu, dẫn đến lỗi không rõ ràng đối với mã hợp lý và hợp lệ trước đó. Vấn đề này dự kiến ​​sẽ được khắc phục sớm.

Bạn có thể thấy rằng khi bạn thêm cờ đó, mã của bạn cũng trở nên mơ hồ. Ví dụ của bạn là loại mã hợp lý và hợp lệ trước đây mà clang đang bảo vệ chống lại ở đây. Một loại ví dụ tương tự tôi đã thấy:

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>> trước đây thường ổn (sử dụng phiên bản nhị phân), nhưng bây giờ trở nên mơ hồ (giữa phiên bản đơn nhất và phiên bản nhị phân).

MSVC có thể đưa ra lựa chọn tương tự, nhưng tôi không biết. Câu trả lời đúng theo tiêu chuẩn là cuộc gọi không rõ ràng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.