2015-11-12 44 views
35

Tôi đang phải vật lộn với những gì dường như là một sự mơ hồ trong C++ độ phân giải 11 biểu tượng do việc thực hiện tiêu chuẩn thư viện GNU trong môi trường này:C++ 11 thành viên danh sách khởi sự nhập nhằng

  • Arch Linux 4.2.5 -1 (x86_64)
  • g ++ 5.2.0
  • kêu vang ++ 3.7.0

Ví dụ:

#include <iostream> 
#include <string> 

struct version { 

    unsigned major; 
    unsigned minor; 
    unsigned patch; 

    version(unsigned major, unsigned minor, unsigned patch) : 
    major(major), minor(minor), patch(patch) { } 

    friend std::ostream & operator<<(std::ostream & out, version const& v) { 
    out << v.major << "."; 
    out << v.minor << "."; 
    out << v.patch; 
    return out; 
    } 

}; 

int main(int argc, char ** argv) { 
    version v(1, 1, 0); 
    std::cout << v << std::endl; 
    return 0; 
} 

biên dịch báo lỗi:

error: member initializer 'gnu_dev_major' does not name a non-static data 
    member or base class 
error: member initializer 'gnu_dev_minor' does not name a non-static data 
    member or base class 

Command:

clang++ -std=c++11 -o test *.cpp 

Phạm vi điều hành giải quyết không xuất hiện để được áp dụng trong danh sách khởi tạo thành viên vì vậy tôi không thể tìm ra cách để giải quyết sự mơ hồ. Mẫu này biên dịch tốt mà không có cờ C++ 11.

+0

Nó cũng biên dịch tốt với MSVC 2015 –

+4

Vấn đề tương tự tìm thấy ở đây [macro lớn và nhỏ quy định tại sys/sysmacros.h kéo bằng ] (http://stackoverflow.com/questions/22240973/major-and- nhỏ-macros-được định nghĩa-in-sys-sysmacros-h-kéo-in-by-iterator) –

+0

@ Myria chúng là các macro được xác định bởi gcc – bolov

Trả lời

40

Một cách khác là sử dụng niềng răng:

version(unsigned major, unsigned minor, unsigned patch) : 
    major{major}, minor{minor}, patch{patch} { } 

Sau đó, các macro sẽ không can thiệp, vì họ là macro chức năng giống như và cần dấu ngoặc đơn để được gọi.

+0

câu trả lời tuyệt vời! giải pháp tốt hơn so với các macro không xác định –

+7

@ChrisHutchinson * "giải pháp tốt hơn undefining" * Tôi không biết về điều đó; Họ không nên có mặt ở nơi đầu tiên vì họ không thực hiện định danh bảo lưu. Tôi thích '# undef'ing chúng. (Upvoted này quá, vì nó là một giải pháp hợp lệ và sạch sẽ cho những người muốn sử dụng những macro.) –

+0

Thú vị - đó là một [lợi ích bất ngờ của brace-initialization.] (Http://stackoverflow.com/q/33444814/1858225) –

9

/usr/include/sys/sysmacros.h đã macro sau được xác định:

# define major(dev) gnu_dev_major (dev) 
# define minor(dev) gnu_dev_minor (dev) 
# define makedev(maj, min) gnu_dev_makedev (maj, min) 

vẻ như bạn phải undef chúng hoặc sử dụng tên khác

19

Từ nỗ lực biên soạn riêng tôi, nó trông giống như glibc đang làm điều gì đó ngu ngốc và #define nhập các từ viết thường.

Khi tôi thêm thông tin sau đây sau #include giây, nó sẽ biên dịch.

#undef major 
#undef minor 
15

Dường như majorminor là macro được định nghĩa trong sys/sysmacros.h đang được đưa vào bởi <iostream>, đó là vấn đề vì các tên are not reserved for the implementation. Lưu ý nếu mã bị giảm và chúng tôi chỉ bao gồm sys/sysmacros.h trực tiếp cùng một vấn đề sẽ xảy ra.

Khi tôi biên dịch này với clang on Wandbox tôi nhận được lỗi thông tin mới hơn này cho phép chúng ta nhìn thấy nơi các cuộc xung đột đến từ:

usr/include/x86_64-linux-gnu/sys/sysmacros.h:67:21: note: expanded from macro 'major' 
# define major(dev) gnu_dev_major (dev) 
        ^~~~~~~~~~~~~~~~~~~ 

usr/include/x86_64-linux-gnu/sys/sysmacros.h:68:21: note: expanded from macro 'minor' 
# define minor(dev) gnu_dev_minor (dev) 
        ^~~~~~~~~~~~~~~~~~~ 

Chúng ta có thể tìm thấy điều này được ghi lại trong báo cáo lỗi sau identifier major macro expanded into gnu_dev_major:

The problem is that g++ adds -D_GNU_SOURCE and major() is a macro in _GNU_SOURCE (or _BSD_SOURCE or when no feature set is requested).

You can always #undef major after including headers.

và:

makedev(), major() and minor() should be functions, not macros.

It looks they were introduced in GNUC >= 2 in sys/sysmacros.h for backward compatibility. It is not a good idea.

Fiddling with macros is dangerous since it pollutes user name space.

và vì vậy chúng tôi có thể thấy undef các macro là một trong những giải pháp và nó là tiếc là giải pháp khuyến khích vì đây là một lỗi sẽ không sửa chữa:

There will be no change. If some code does not like the macros, add #undefs after the appropriate #include. The macros are part of the API and removing them only causes problems.

Chúng ta có thể sử dụng {} trong intializer thành viên nhưng điều này đòi hỏi phải thay đổi các loại của các tham số khi rời khỏi chúng dưới dạng int sẽ là một chuyển đổi thu hẹp không được phép. Tất nhiên thay đổi tên cũng là một giải pháp có thể.

Cập nhật

tôi đệ đơn glibc bug report. Có một số câu hỏi về việc đây có thực sự là một lỗi gcc hay glibc, các chi tiết có liên quan không.

+0

Nếu nó chưa tồn tại, tôi sẽ gửi một báo cáo lỗi mới chống lại glibc. Đây là kết quả của sự tương tác khó chịu của nhiều tệp tiêu đề: '_GNU_SOURCE' gây' stdlib.h' để bao gồm 'sys/types.h' và nó gây' sys/types.h' để bao gồm 'sys/sysmacros.h' . Việc xếp tầng của hai hành vi này hoàn toàn không chủ ý và không mong muốn. –

+3

Tôi đồng ý với R ..: nộp báo cáo lỗi mới (trong bugzilla ngược dòng, không phải của Red Hat: https://sourceware.org/bugzilla/) Thái độ của người bảo trì glibc đối với loại điều này đã thay đổi đáng kể kể từ năm 2004. – zwol

+0

@R .. đã gửi báo cáo lỗi và được liên kết trong câu trả lời của tôi –

Các vấn đề liên quan