Вывод аргумента шаблона для шаблонов классов в С++ 17: я делаю это неправильно?

Согласно https://gcc.gnu.org/projects/cxx-status.html, версия 7 g++, используемая с флагом -std=c++1z, поддерживает вывод аргументов шаблона для шаблонов классов.

Я ожидаю компиляции следующего кода, тем более что 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> (чтобы можно было использовать полиморфизм)?


person Georg    schedule 06.09.2017    source источник
comment
В этом сообщении об ошибке утверждается, что * в Base *pt_base не разрешено. *pt_base является декларатором, но не идентификатором-декларатором (например, недекорированным идентификатором). Однако я не могу найти это правило нигде в N4687.   -  person aschepler    schedule 07.09.2017
comment
@aschepler Правила дедукции срабатывают только в определенных местах. А в исходном предложении явно говорилось такие вещи, как указатели, функции и ссылки.   -  person Barry    schedule 07.09.2017
comment
Кроме того, вывод класса шаблона происходит во время компиляции. В ситуациях, когда вам разрешено написать только Base, компилятор решит, действительно ли это означает Base<someType> или что-то еще. Base не является типом. Таким образом, у вас не может быть ни одной переменной, указывающей на Derived<someType> или Derived<someType2> во время выполнения, если только они оба не наследуют какой-то общий тип. Вам может понадобиться std::any или std::variant для возвращаемого типа его getValue().   -  person aschepler    schedule 07.09.2017
comment
Если бы vector<Base*> был допустимым, стирание типа поддерживалось бы языком напрямую...   -  person Walter    schedule 07.09.2017
comment
@Barry [dcl.type.class.deduct] Если заполнитель для выведенного типа класса появляется как decl-specifier в decl-specifier-seq объявления инициализации переменной заполнитель заменяется возвращаемым типом функции, выбранной разрешением перегрузки для вывода шаблона класса ([over.match.class.deduct]). Согласно письму, это предложение будет применяться. Хотя в этом примере это потерпит неудачу, потому что ни один из придуманных конструкторов для Base не может принимать указатель. Но при строгом чтении я думаю, что std::vector&& v(1,1); может быть разрешено. Мне кажется Дефект.   -  person aschepler    schedule 07.09.2017
comment
@Barry Эта статья, безусловно, самая плохая письменная работа, которую я когда-либо читал. Но тогда я не очень люблю всю эту функцию.   -  person T.C.    schedule 07.09.2017
comment
@aschepler P0620 удалил первоначальное ограничение, по-видимому, непреднамеренно (цель этого редактирования состояла в том, чтобы удалить требование для инициализатора , если я правильно понял). Я думаю, это то, что вы получаете за функцию, которая была переработана и исправлена ​​​​до самой последней секунды :(   -  person T.C.    schedule 07.09.2017


Ответы (1)


Вывод аргумента шаблона класса работает для объявления экземпляров типов классов:

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));
person Barry    schedule 06.09.2017