2017-09-06 26 views
2

根據 https://gcc.gnu.org/projects/cxx-status.html,g ++的版本7與標記-std=c++1z一起使用,支持類模板的模板參數推導。C++中類模板的模板參數推導17:我做錯了嗎?

我希望下面的代碼進行編譯,特別是作爲Base是一個抽象類,因此:
1.編譯器知道沒有的Base實例可被創建的;
2.指向基地pt_base的指針指向明確定義的實例(即Derived<int>{42}),其中類型(int)是明確的。

template<typename ValueType> 
class Base { 
public: 
    virtual ValueType getValue() = 0; 
}; 

template<typename ValueType> 
class Derived : public Base<ValueType>{ 
public: 
    Derived(ValueType argt){ value = argt; } 
    virtual ValueType getValue(){ return value; } 
    ValueType value; 
}; 

int main(){ 
    Base *pt_base = new(Derived<int>{42}); // *ERROR* 
    delete pt_base; 
} 

然而,它does not compile。 G ++抱怨「模板佔位符類型」Base「後面必須跟一個簡單的聲明符號」;如果我理解正確,它不會推導出模板參數。
很遺憾,因爲我想動態地決定哪個派生類pt_base指向(可能是來自類Derived<someType>或類Derived2<someType2>的對象)。這樣,數組或vector<Base *>可以存儲指向各種派生類的對象的指針。

對於C++ 17,GCC只有experimental support,並且我沒有訪問其他編譯器的權限,所以儘管我收到編譯錯誤,但我不確定我的代碼是否有錯。你怎麼看?
我們如何動態地決定pt_base指向Derived<someType>Derived2<someType2>(因此可以使用多態性)的對象?

+1

該錯誤消息聲明'Base * pt_base'中的'*'是不允許的。 '* pt_base'是一個_declarator_,但不是_declarator-id_(比如一個未修飾的標識符)。不過,我無法在N4687的任何地方找到這條規則。 – aschepler

+0

@aschepler演繹規則只是在某些地方進行。 [原始提案](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0091r3.html)明確排除了諸如指針,函數和引用之類的內容。 – Barry

+1

此外,模板類扣除發生在編譯時。在你被允許編寫'Base'的情況下,編譯器會決定它是否實際上意味着'Base '或其他什麼。 'Base'不是一種類型。因此,在運行時,您不能在「派生的」或「派生的」上有單個變量點,除非它們實際上都繼承了一些常見類型。您可能需要一個'std :: any'或'std :: variant'作爲其''getValue()'的返回類型。 – aschepler

回答

7

類模板參數推導適用於聲明類類型的實例:

Derived d(42); 

或者新的表達式:

auto p = new Derived(42); 

或函數式的轉換:

foo(Derived(42)); 

它確實不適用於聲明指針。


您將不得不簡單地提供模板參數,因爲您一直都必須這樣做。或者,我猜:

template <class T> Base<T>* downcast(Base<T>* p) { return p; } 
auto pt_base = downcast(new Derived(42)); 
+1

downcast函數是一個很好的技巧,謝謝 – Georg