C++17中类模板的模板参数推导:我做错了吗?

8
根据https://gcc.gnu.org/projects/cxx-status.html,使用标志-std=c++1z的g++ 7版本支持类模板的模板参数推导。
我期望以下代码能够编译通过,特别是因为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;
}

然而,它无法编译。G++抱怨说“模板占位符类型'Base'必须跟随一个简单的声明符标识符”;如果我理解正确,它没有推导出模板参数。
很遗憾,因为我想动态决定pt_base指向哪个派生类(可以是来自类Derived<someType>或类Derived2<someType2>的对象)。这样,一个数组或vector<Base *>可以存储指向各种派生类对象的指针。

GCC目前只实验性地支持C++17,而且我没有其他编译器的访问权限,所以尽管我得到了编译错误,但我不确定我的代码是否有错。你认为呢?
我们如何动态决定pt_base指向Derived<someType>Derived2<someType2>中的一个对象(以便可以使用多态性)?


1
该错误信息声称 Base *pt_base 中的 * 不被允许。*pt_base 是一个声明符,但不是一个声明符标识符(比如未装饰的标识符)。我在 N4687 中找不到这个规则。 - aschepler
@aschepler 这些推导规则仅适用于某些特定情况。而原始提案明确排除了指针、函数和引用等内容。 - Barry
1
此外,模板类推导发生在编译时。在允许仅写Base的情况下,编译器将决定它实际上是否意味着Base<someType>或其他内容。Base不是一种类型。因此,除非它们实际上都继承了某个公共类型,否则您无法使单个变量在运行时指向Derived<someType>Derived<someType2>。您可能需要使用std::anystd::variant作为其getValue()的返回类型。 - aschepler
如果vector<Base*>是有效的,类型擦除将直接由语言支持... - Walter
1
@Barry 那篇论文是我读过的写得最差的论文。但是,我并不是这个“特性”的粉丝。 - T.C.
显示剩余2条评论
1个回答

10

类模板参数推导适用于声明类类型的实例:

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));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接