2012-10-17 22 views
5

xem xét mãC++ chuyên môn hóa lỗi phân biệt khi đi qua một mảng const

 template <class A> 
    class B; 

    template <class A> 
    class B<const A>{}; 

    template <class A, int N> 
    class B<A[N]>{}; 

    template <class A> 
    class B<A*>{}; 

    template <class A> 
    class B<A&>{}; 

Các instantiations mẫu sau hoạt động tốt:

 A<int*&> 
    A<const int*> 
    A<int*[3]> 

nhưng sau một không hoạt động:

 A<const int[3]> 

Có một số lý do khiến kết hợp cụ thể này không hợp lệ hoặc có thể là lỗi với g ++ 4.6 .3?

Nhân tiện tôi đã xoay xở để giải quyết vấn đề này bằng cách sử dụng SFINAE và tăng :: disable_if <>, vì vậy ít nhất vấn đề được giải quyết.

EDIT

tôi quên đề cập đến rằng lỗi trong câu hỏi là một mơ hồ lớp mẫu instantiation và nó không thể quyết định giữa sự quá tải cho const hoặc quá tải cho một mảng.

EDIT2

này không có gì để làm với con trỏ, đây là bối cảnh đầy đủ:

Tôi sẽ thông qua cuốn sách C++ Template Metaprogramming và đang làm câu hỏi 2-3 (Chương 2 câu hỏi 3) có nội dung:

Sử dụng các kiểu tính năng đặc điểm để triển khai mẫu lớp type_descriptor, có trường hợp, khi được truyền trực tuyến, in loại tham số mẫu của chúng: LƯU Ý: chúng tôi không thể sử dụng RTTI có cùng tác dụng kể từ, theo đoạn 18.5.1 [lib.type.info] đoạn 7 của tiêu chuẩn, typeid (T) .name() không được bảo đảm để trả lại kết quả có ý nghĩa.

Giải pháp của tôi (bao gồm cả thực hiện giải pháp cho các lỗi biên dịch) như sau:

//QUESTION 2-3 
    template <class T, class enable = void> 
    struct type_descriptor 
    { 
     std::string operator()() const 
     { 
     return "Unknown"; 
     } 
    }; 

    //specializations for primitive types 
    #define TYPE_DESC_SPEC(type) template <> \ 
     struct type_descriptor<type,void>  \ 
     {std::string operator()() const{return #type;}}; 

    TYPE_DESC_SPEC(int) 
    TYPE_DESC_SPEC(long) 
    TYPE_DESC_SPEC(void) 
    TYPE_DESC_SPEC(short) 
    TYPE_DESC_SPEC(unsigned char) 
    TYPE_DESC_SPEC(unsigned short) 
    TYPE_DESC_SPEC(unsigned long) 

    //specializations for modifiers *, const, &, and [N] 

    template <class T> 
    struct type_descriptor<T&,void> 
    {std::string operator()(){return type_descriptor<T>()() + " &";}}; 

    template <class T> 
    struct type_descriptor<T*,void> 
    {std::string operator()(){return type_descriptor<T>()() + " *";}}; 

    //Replace void with what's in the comment for the workaround. 
    template <class T> 
    struct type_descriptor<const T, void/*typename boost::disable_if<boost::is_array<T> >::type*/> 
    {std::string operator()(){return type_descriptor<T>()() + " const";}}; 

    template <class T> 
    struct type_descriptor<T(*)(),void> 
    {std::string operator()(){return type_descriptor<T>()() + " (*)()";}}; 

    template <class T, class U> 
    struct type_descriptor<T(*)(U),void> 
    {std::string operator()(){return type_descriptor<T>()() + " (*)(" + type_descriptor<U>()() + ")";}}; 

    template <class T, int N> 
    struct type_descriptor<T[N],void> 
    { 
     std::string operator()() 
     { 
     std::stringstream s; 
     s << type_descriptor<T>()() << " [" << N << "]"; 
     return s.str(); 
     } 
    }; 

    template <class T> 
    struct type_descriptor<T[],void> 
    {std::string operator()(){return type_descriptor<T>()() + " []";}}; 

    //Now overload operator<< to allow streaming of this class directly 

    template <class T> 
    std::ostream & operator<<(std::ostream & s, type_descriptor<T> t) 
    { 
     return s << t(); 
    } 
    //END QUESTION 2-3 

sử dụng mẫu là:

 std::cout << "\nQuestion 2-3 results\n"; 
     std::cout << type_descriptor<int*>() << std::endl; 
     std::cout << type_descriptor<int*[3]>() << std::endl; 
     std::cout << type_descriptor<std::string*>() << std::endl; 
     std::cout << type_descriptor<const int&>() << std::endl; 
     std::cout << type_descriptor<const int *const&>() << std::endl; 
     std::cout << type_descriptor<int[4]>() << std::endl; 
     std::cout << type_descriptor<int(*)()>() << std::endl; 
     std::cout << type_descriptor<int*&(*)(const char &)>() << std::endl; 
     std::cout << type_descriptor<int*&>() << std::endl; 
     std::cout << type_descriptor<int[]>() << std::endl; 
     std::cout << type_descriptor<const long[]>() << std::endl; 

và đầu ra tương ứng là (khi thực hiện giải pháp là trong, nếu không nó không được biên dịch vào cái cuối cùng):

 
int * 

int * [3] 

Unknown * 

int const & 

int const * const & 

int [4] 

int (*)() 

int * & (*)(Unknown const &) 

int * & 

int [] 

long const [] 

Vì vậy, C++ có thể khác iate con trỏ và mảng cho các tham số mẫu, có thể một cách chính xác, đệ quy, các loại hợp chất riêng biệt và xuất kết quả chính xác, ngoại trừ const A[]. Nó cần được giúp đỡ với điều đó

+0

Hãy đoán điều này - nhưng tôi nghĩ 'const int [3]' phân rã thành 'const int *' –

+0

@AdrianCornish, không phải vậy, hãy xem bản chỉnh sửa. Bên cạnh đó nếu đó là ví dụ hợp lệ thứ ba tôi đưa ra cũng không nên hoạt động. – SirGuy

+0

3rd sẽ hoạt động vì 'const int *' khác với 'int *' - cố gắng (không thành công) để tìm phần tiêu chuẩn ghi lại sự phân rã ;-) –

Trả lời

1

Một loại mảng có loại phần tử const là cả một loại đủ điều kiện const (const áp dụng hai chiều) và một loại mảng.

Vì vậy, bạn nên khắc phục các chuyên môn.

+0

Tại sao nó như vậy cho mảng và không cho con trỏ hoặc tài liệu tham khảo? – SirGuy

+0

vì nó không có ý nghĩa đối với con trỏ. con trỏ có thể là const và có thể trỏ đến const. và các tham chiếu là một sự vô hướng cũng có thể khái niệm cũng có hai const khác nhau nhưng vì một tham chiếu không thể thay đổi để chỉ những thứ khác nhau nên const trên chính tham chiếu bị cấm. ở phía bên kia, giá trị của một mảng không có gì hơn tất cả các phần tử của nó, mà không có sự gián tiếp. do đó, có nghĩa là const áp dụng hai chiều. –

+0

Có lợi thế nào đối với định nghĩa này khi xem xét 'const int []' là một mảng của const ints? Tôi có nghĩa là theo ý nghĩa rằng các chuyên môn mẫu ở trên sẽ không mơ hồ và chuyên môn hóa mảng là những gì sẽ được khởi tạo. – SirGuy

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