2013-01-08 45 views
11

Tôi đã viết một thư viện nhỏ có sử dụng rất nhiều C++ 11 kỹ thuật lập trình meta và CRTP, và nó biên dịch tốt với g ++ 4.7.2Clang và Intel không biên dịch mã CRTP này

Bây giờ, tôi cố gắng biên dịch nó với Intel icpc 13.0.0.079 và nó tạo ra hàng trăm lỗi. Vì vậy, tôi cố gắng tách biệt các vấn đề này với nhau.

Vì vậy, trước hết, hãy xem xét mã này, mà biên dịch không có vấn đề dưới g ++ 4.7.2

#include <iostream> 

template<template<typename> class Crtp, typename Type> 
struct Base {}; 

template<typename Type> 
struct Derived : public Base<Derived, Type> 
{ 
    Derived(): Base<Derived, Type>() {;} 
}; 

int main() 
{ 
    Derived<int> x; 
    return 0; 
} 

Cả ICPC và kêu vang thất bại để biên dịch mã này:

test_crtp.cpp(26): error: type "Derived<Type>::Derived" is not a class template 
     Derived(): Base<Derived, Type>() {;} 
        ^

test_crtp.cpp(26): error: "Base" is not a nonstatic data member or base class of class "Derived<int>" 
     Derived(): Base<Derived, Type>() {;} 
       ^
      detected during instantiation of "Derived<Type>::Derived() [with Type=int]" at line 31 

compilation aborted for test_crtp.cpp (code 2) 

Vì vậy, nó là một lỗi trong intel và clang, hoặc trong g ++? Nếu nó trong intel và clang, bạn có nghĩ rằng nó sẽ được giải quyết trong một phiên bản tương lai?

+0

Đó là một câu hỏi hay, nhưng thường CRTP không bận tâm với tham số mẫu-template, nhưng chỉ có lớp Derived vượt qua loại. 'template struct Base; mẫu struct Có nguồn gốc: Cơ sở < Derived> {...}; 'bình thường hơn. –

+0

... nếu bạn muốn truyền 'Type', có thể bạn có thể có' typedef' trong 'Derived' để hiển thị nó ... – Nim

+1

Tên định danh' Derived', bên trong lớp riêng của nó, kiểu hoàn chỉnh 'Có nguồn gốc '.Đây được gọi là tên lớp * được tiêm *. Tôi nghĩ rằng đây là một lỗi với GCC. – Xeo

Trả lời

7

Bên trong lớp Derived, tên Derived là lớp (được khởi tạo), không phải là mẫu lớp. Thay vào đó, hãy thử Base< ::Derived, Type> (hãy cẩn thận để khoảng trống giữa < và: :).

+4

Lưu ý: lý do cho không gian là '<:' có thể được hiểu là [digraph] (http://en.wikipedia.org/wiki/Digraphs_and_trigraphs), và do đó '<::' sẽ được xem là ' [: 'sau khi tiền xử lý ... –

+5

Trong C++ 11, bạn chỉ có thể viết' <:: Derived', '<:' không được hiểu là một biểu đồ trong danh sách đối số mẫu. – Xeo

+1

@MatthieuM. Cũng lưu ý rằng điều đó chỉ đúng với C++ trước C++ 11 (hoặc GCC <4.8) = –

6

Trong phần 9.2.3 của C++ Mẫu Hướng dẫn đầy đủ (Amazon), có một cuộc thảo luận về tên lớp được tiêm. Để báo giá:

Mẫu lớp cũng có tên lớp được chèn. Tuy nhiên, chúng có tên là lạ hơn tên lớp được tiêm thông thường: Chúng có thể được theo sau bởi đối số mẫu (trong trường hợp chúng được nhập mẫu lớp tên), nhưng nếu chúng không được theo sau bởi đối số mẫu, chúng đại diện cho lớp các tham số như các đối số của nó (hoặc, cho một chuyên môn một phần, các đối số chuyên môn hóa của nó là ). Điều này giải thích tình huống sau đây:

template<template<typename> class TT> 
class X {}; 

template<typename T> 
class C 
{ 
    Ca;  // OK: same as ''C<T> a;'' 
    C<void> b; // OK 
    X<C> c; // ERROR: C without a template argument list 
       // does not denote a template 
    X<::C> d; // ERROR: <: is an alternative token for [ 
    X< ::C> e; // OK: the space between < and :: is required 
} 

Lưu ý làm thế nào tên không đủ tiêu chuẩn đề cập đến tên tiêm và không phải là coi là tên của mẫu nếu nó không được theo sau bởi một danh sách các luận mẫu . Để bù lại, chúng tôi có thể buộc tên của mẫu được tìm thấy bằng cách sử dụng trình độ phạm vi tệp ::. Công trình này, nhưng chúng tôi phải cẩn thận không tạo mã thông báo được gọi là <:, được hiểu là dấu ngoặc vuông trái. Mặc dù tương đối hiếm, lỗi như vậy dẫn đến chẩn đoán rắc rối.

Vì vậy, những gì xảy ra trong mã của bạn là Base<Derived, Type> đang được hiểu là Base<Derived<Type>, Type> không đúng định dạng. Do đó, bạn cần sử dụng trình độ phạm vi :: với khoảng cách giữa < để tránh hiển thị hình ảnh.

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