2017-09-06 78 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