2013-01-08 40 views
11

我寫了使用大量的C++ 11元編程技術和CRTP一個小型圖書館,並與G ++ 4.7.2鏘和英特爾無法編譯這個CRTP代碼

現在編譯好了,我試着使用英特爾icpc 13.0.0.079進行編譯,並生成數百個錯誤。所以我試圖逐個隔離問題。

因此,首先,考慮下面的代碼,這在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; 
} 

兩個ICPC和鐺沒有問題編譯編譯失敗驗證碼:

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) 

因此,它是一個在英特爾和叮噹,或在g ++中的錯誤?如果它在英特爾和鏗鏘中,你認爲它將在未來的版本中得到解決嗎?

+0

這是一個很好的問題,但通常CRTP不會打擾模板模板參數,但只是讓Derived類傳遞類型。 'template struct Base; template struct Derived:Base < Derived> {...};''是比較正常的。 –

+0

...如果你想傳播'Type',可能你可以在'Derived'中有一個'typedef'來暴露它... – Nim

+1

標識符'Derived'名稱,在它自己的類中,完整類型'Derived '。這被稱爲*注入*類名稱。我認爲這是GCC的一個錯誤。 – Xeo

回答

7

在類Derived中,名稱Derived引用(實例化)類,而不是類模板。請嘗試使用Base< ::Derived, Type>(請小心在<和:)之間留出空格。

+4

注意:空格的原因是'<:'可能被解釋爲[digraph](http://en.wikipedia.org/wiki/Digraphs_and_trigraphs),因此'<::'將被視爲' [:'preprocessing ... –

+5

在C++ 11中,你可以直接寫'<:: Derived','<:'不會被解釋爲模板參數列表中的二合字母。 – Xeo

+1

@MatthieuM。另請注意,在C++ 11(或GCC <4.8)= –

6

C++模板完整指南Amazon)的第9.2.3節中,討論了注入類名。引用:

類模板也有注入的類名。然而,它們是 比普通的注入類名稱更陌生:它們可以跟着 模板參數(在這種情況下,它們是注入類模板 名稱),但如果它們沒有跟隨模板參數,它們將代表它的類,其中 參數作爲參數(或者,對於部分特化,它的特化參數)。這說明 以下情況:

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 
} 

注不合格的名字怎麼是指注入的名字,而不是 考慮到模板的名稱,如果後面沒有的 模板參數列表。爲了彌補,我們可以通過使用文件範圍限定符::來強制找到 模板的名稱。這個作品, ,但我們必須小心不要創建一個所謂的有向圖標記 <:,它被解釋爲左括號。雖然比較少見,但這種錯誤會導致錯誤的診斷。

那麼在你的代碼中會發生什麼Base<Derived, Type>被解釋爲Base<Derived<Type>, Type>這是不合格的。因此,您需要使用範圍限定符::,並使用<之間的空格來避免有向圖。