2016-03-02 69 views
4

下面將編譯GCC 5.2,但不與Visual Studio 2015年CRTP編譯錯誤

template <typename Derived> 
struct CRTP { 
    static constexpr int num = Derived::value + 1; 
}; 

struct A : CRTP<A> { 
    static constexpr int value = 5; 
}; 

它抱怨A沒有一個成員名爲value。 如何修復代碼以便在兩個編譯器上編譯?還是完全違法?

+0

它也無法編譯的鏗鏘。 –

+0

它是非法的語法,GCC只是僥倖嗎? – prestokeys

+1

我不確定,但它看起來應該是非法的,否則你可能有'num = Derived :: value'和'value = CRTP :: num' –

回答

6

請嘗試使其成爲constexpr函數。您現在設置的方式現在嘗試訪問不完整的類型。
由於模板成員函數只會在首次使用時初始化,因此A將由該點完全定義。

#include <iostream> 

template <typename Derived> 
struct CRTP { 
    static constexpr int num() { return Derived::value + 1; } 
}; 

struct A : CRTP<A> { 
    static constexpr int value = 5; 
}; 

int main() 
{ 
    std::cout << A::num(); 
    return 0; 
} 

實時查看here

4

的問題是在這裏:

template <typename Derived> 
struct CRTP { 
    static constexpr int num = Derived::value + 1; 
           ↑↑↑↑↑↑↑↑↑ 
}; 

截至CRTP<A>實例化時,A不是一個完整的類呢,所以你不能實際上訪問它的靜態成員。

一個解決辦法是在num通過作爲一個獨立的模板參數:

template <typename Derived, int N> 
struct CRTP { 
    static constexpr int num = N; 
}; 

struct A : CRTP<A, 5> { 

}; 
+0

爲什麼'CRTP :: num'的初始值設定項需要在'CRTP '被實例化的時候實例化?你能提供一個參考標準嗎? – HighCommander4

+0

我發現的是'[temp.inst] p9':「類模板的隱式實例化不會導致該類的任何靜態數據成員被隱式地實例化」 「。 – HighCommander4

+0

@HighCommander4這與成員的定義有關 - 聲明仍然需要被解析並且有效,它不在OP的例子中作爲「Derived」還沒有完成。 – Barry