2017-03-13 41 views
1

我想要一個Iterable<T>類允許在Object上迭代一般。 (T假定是派生的對象)
但是,當定義我的通用Iterable<T>繼承對象Iterable<Object>的專用版本時,只要類實例化,我得到一個編譯錯誤在ngng和gcc(但不是MSVC)。 錯誤是Iterable<Object>是一個不完整的類型。無法繼承clang和gcc中相同類的顯式模板特化

第一個問題是爲什麼,因爲我預計編譯器會在那裏使用Iterable的顯式實例化。 第二個問題是,這將是一個可能的解決方案實現相同的結果,理想的結果是,與未對象應該滿足任意t的Iterable<T>Iterable<Object>

#include <functional> 

class Object 
{}; 

class Foo : public Object 
{}; 

template <class T> 
class Iterable : public Iterable<Object> 
{ 
public: 
    virtual void iterate(const std::function<void(T&)>& callback) const = 0; 
}; 

template <> 
class Iterable<Object> 
{ 
public: 
    virtual void iterate(const std::function<void(Object&)>& callback) const = 0; 
}; 
+0

這是一種遞歸定義。我的意思是,你正在嘗試專門化一些需要專業化的東西。 – perencia

+0

'Iterable '不依賴名字 –

+0

@perencia但我期望專業化不依賴於一般定義。我理解你的意思是,它實際上是這樣嗎? – N0vember

回答

1

的錯誤發生,因爲你的關係從尚未定義的類繼承,所以你必須做的是定義類,然後定義一個專門化。編譯器不能實例化尚未定義的模板。您可能會發現有關CRTP的內容。見http://eli.thegreenplace.net/2011/05/17/the-curiously-recurring-template-pattern-in-c

要解決一個對象必須滿足is-an-object條件的問題,我將在對象中創建一個接口,該接口包含它將用於的所有內容並創建一個非模板迭代函數。模板的重點在於它們是通用的,可以用於無關的類型。

+0

我知道CRTP,但我真的不知道它在這裏有什麼用處,因爲當T是一個對象的派生時,我的目標是讓一個可重用的成爲一個可重用的。 但是,由於您解釋了潛在的原因,我試圖在答案中提出解決方法。 – N0vember

0

繼我不能在一般定義中使用專業化的答案後,我試着想出一個解決方法,這是我目前看到的最好的:隨時提出更好的解決方案。

template <class T, bool object = std::is_base_of<Object, T>::value> 
class Iterable 
{ 
public: 
    virtual void iterate(const std::function<void(T&)>& callback) const = 0; 
}; 

template <class T> 
class Iterable<T, true> : public Iterable<Object> 
{ 
public: 
    virtual void iterate(const std::function<void(T&)>& callback) const = 0; 
}; 
+0

您可以在通用定義中使用專業化,但您使用的專業化必須取決於其中一個模板參數的相關名稱。你可以編譯器把'Iterable '作爲依賴名稱......參見[example](http://coliru.stacked-crooked.com/a/9390194c38dc83d2) –

+0

@ W.F。有趣。我寧願選擇評分最高的答案,因爲它是最乾淨和最簡單的答案,但我在那裏學到了一些東西。 – N0vember

3

您可以輕鬆地先聲明瞭主模板,然後專門它,然後將其定義解決這個問題:

template <class T> 
class Iterable; 

template <> 
class Iterable<Object> 
{ 
public: 
    virtual void iterate(const std::function<void(Object&)>& callback) const = 0; 
}; 

template <class T> 
class Iterable : public Iterable<Object> 
{ 
public: 
    virtual void iterate(const std::function<void(T&)>& callback) const = 0; 
}; 

[Live example]

然而,聽取由活生生的例子產生的警告:Iterable<T>::iterate不會覆蓋Iterable<Object>::iterate,因爲它們的參數具有不同的類型。你必須實現Iterable<T>的所有類別T以外的Object

+0

哇。我以某種方式假定這不起作用。我認爲一般定義首先被評估,不管順序如何。我很驚訝地發現訂單改變了這裏的一切。 (和聲明,但我已經有一個爲我所有的類都向前聲明。) 至於實際的代碼警告'可迭代'實現了'可迭代'因此,警告不會觸發定義的迭代函數。 – N0vember

+0

@N0vember在C++中,順序非常重要,特別是*有模板。引用C++ 11,[temp.expl.spec] 14.7.3/7(強調我的):「函數模板,類模板等的顯式特化聲明的放置會影響程序是否爲 - 根據顯式專門化聲明的相對定位及其在上下文中指定的翻譯單元中的點的實例化**在編寫專業化時,請注意其位置;或者使其編譯爲試驗以點燃其自焚。**「 – Angew