2009-08-11 72 views
3

目前我有一個令人沮喪的問題,正向聲明和模板函數。我一直在嘗試使用Google進行修改,但目前爲止沒有任何工作。下面的代碼片段:正向聲明和模板函數錯誤

class TaskScheduler; --> //forward declaration of ‘struct TaskScheduler’ 
// 
// 

class TaskEvent { 
// 
// 
}; 

class HostTask { 
// 
// 
}; 

template<class T> inline HostTask* 
findT(TaskScheduler* tss, T* e) 
{ 
    map<int, HostTask*>::iterator it; 
    bool bEq = false; 
    for(it = tss->tasks_.begin(); it != tss->tasks_.end(); it++) { --> //error: invalid use of incomplete type ‘struct TaskScheduler’ 
    if(dynamic_cast<TaskEvent*>(e)) 
     bEq = dynamic_cast<TaskEvent*>(e)->equal(it->second->ev_); 
    else if(dynamic_cast<HostTask*>(e)) 
     bEq = dynamic_cast<HostTask*>(e)->equal(it->second); 
    if(bEq) { 
     return it->second; 
    } 
} 
return NULL; 
} 
// 

//class TaskScheduler definition 
class TaskScheduler : virtual public HCIEventsHandler { 
friend HostTask* findT<TaskEvent>(TaskScheduler* tss, TaskEvent* e); //findT function is used here 
// 
// 
}; 

這裏是一個在代碼中顯示爲好,我已經得到了錯誤消息: ./bt-taskscheduler.h:159:錯誤:向前聲明'struct TaskScheduler' ./bt-taskscheduler.h:229:error:invalid use of incomplete type'struct TaskScheduler'

有人能告訴我這段代碼出了什麼問題嗎?任何幫助表示讚賞..

回答

5

在您使用tss->tasks_findT的定義,取消引用一個指針類型的對象TaskScheduler所以你需要的結構的完整定義,不只是一個向前聲明可見在這一點上程序。

struct TaskScheduler的定義需要在findT函數模板的定義之前出現。

1

您正在for循環頭「tss-> tasks_.begin()」中使用TaskScheduler類。編譯器不知道這個類是否有「tasks_」成員。

這不是你的模板的問題,在頭文件中內聯的任何函數都會導致相同的錯誤。該類的前向聲明只允許你聲明指向該類的指針(或引用),或者將這個類對象作爲參數傳遞。你不能「使用」這個類(調用它的方法或獲取成員數據),直到你完全定義你的類。

1

由於您使用的findT功能的TaskScheduler的定義,你有兩個選擇:

  • 移動的TaskScheduler的findT模板函數上述定義
  • 製作的TaskScheduler的findT功能的第二個模板

像這樣:

template< class U, class T> 
inline HostTask* findT(U* tss, T* e) 
{ 
    //... 
} 
0

正如其他海報所提到的,您正在取消引用一個指向TaskScheduler的指針,而沒有定義類型,這將導致錯誤,就像在任何定義中一樣。 (我知道MSVC在這方面是不正確的,但我不知道它是否會接受上面的代碼*)。你可能會困惑的是你的代碼可能適用於一些編譯器,甚至現代的編譯器(我知道MSVC在這方面是不正確的,但我不知道它是否會接受上述代碼*)。這些編譯器沒有正確實施所謂的兩階段名稱查找

兩階段名稱loopkup是模板中使用的名稱查找方法比一些編譯器使用的更簡單的形式更可預測的方法。在更簡單的形式中,模板定義將被解析並存儲,以便僅在實例化時使用,並且從實例化模板的位置對模板中的所有名稱執行名稱查找。使用兩階段名稱查找,模板中使用的名稱可分爲相關名稱非相關名稱。非依賴名稱是編譯器可以立即解析的名稱 - 任何不依賴模板參數的名稱,直接或間接。定義模板時會立即處理這些名稱。另一方面,相關名稱不能立即解決;它們被存儲,然後當執行實例化時,在模板的上下文中查找,但也在模板被實例化的上下文中查找僅用於argument-dependent lookup只有

下面是一個例子:

void foo (int); 
template <typename T> void bar(T t) { 
    foo(1.0); 
    foo(t); 
} 
void foo (double); 

struct qux {}; 
void foo (qux); 

void baz() { 
    bar (1.0); 
    qux q; 
    bar (q); 
} 

注:我知道我以錯誤的順序得到了簡單的名稱。我很抱歉,但我最後添加了qux,無法重寫我的評論。

bar模板的實例化每次調用foo兩次。第一個調用是非依賴的,所以編譯器在它看到它時立即解析它。其結果是,它調用foo (int),應用轉換,即使稍後會找到更好的定義。這與C++中的其他函數調用沒有區別。棘手的一點伴隨着第二次調用,這是依賴的。 baz中的第一個呼叫請求bar<double>,後者呼叫bar<qux>。實例化的bar嘗試使用T類型的對象調用foo。在double的情況下,由於原語從不使用參數依賴查找,因此只能從bar再次查找結果,並找到foo(int)。但是,如果使用qux調用,則在定義實例化上下文**中均應用了參數相關查找,因此將調用foo(qux)

它可以是一個愚蠢的,但它傾向於做正確的事情。另外,我希望你真的明白這一點;它可能相當混亂。你需要閱讀維基百科鏈接才能完全理解。 * MSVC可能會實現一種較小形式的兩階段名稱查找,它可以正確解析非依賴名稱,但它會考慮依賴名稱模板之後的定義。我忘了它是這樣做還是完全省略了兩階段查找,而我沒有要檢查的程序副本。

**在幾乎所有情況下,實例化上下文都包含定義上下文所做的每個聲明。然而,關鍵字export可能導致這種情況不成立。該關鍵字只在一個編譯器前端實現 - 我想知道爲什麼沒有人實現它? [/諷刺]

+0

確實這個代碼與一些編譯器一起工作..無論如何,謝謝大家的回答..基本上我需要轉發聲明findT模板函數並解決我的代碼結構..謝謝你們.. – bayu 2009-08-12 07:49:49

1

除了前向聲明的麻煩之外,它看起來好像您的findT函數實際上應該是調度程序類的成員函數:它廣泛使用調度程序的數據成員。

這些成員是私人的,所以您需要一種方法來發布它們,並回落到friend聲明中。

因此,無論是讓成員公開還是更好地將findT函數重構爲成員函數。

使它成爲模板化的成員函數也沒有問題。你會自動擺脫朋友聲明。

//class TaskScheduler definition 
class TaskScheduler : virtual public HCIEventsHandler { 
public: 
    template<class T> inline HostTask* findT(T* e) const 
    { 
    map<int, HostTask*>::iterator it; 
    bool bEq = false; 
    for(it = tasks_.begin(); it != tasks_.end(); it++) { 
     if(dynamic_cast<TaskEvent*>(e)) 
      bEq = dynamic_cast<TaskEvent*>(e)->equal(it->second->ev_); 
     else if(dynamic_cast<HostTask*>(e)) 
      bEq = dynamic_cast<HostTask*>(e)->equal(it->second); 
     if(bEq) { 
      return it->second; 
     } 
    } 
    return NULL; 
    } 


};