Ошибка компиляции шаблона с переменным числом аргументов при вызове конструктора по умолчанию

У меня странное поведение в отношении метода шаблона, вызывающего вариативный метод шаблона, и я не могу найти, в чем проблема. Я использую Visual Studio Community 2017.

Ошибка компиляции появляется в следующем методе:

// AScene.hpp
#include "Scriptable.hpp"

template <typename T>
void AScene::initialize_(void) {
    std::shared_ptr<AGameObject> root = std::make_shared<T>();

    // ...
    root->addComponent<Scriptable>(3); // it works (3 is just a random value to bypass the default constructor, see below the Scriptable struct definition)
    root->addComponent<Scriptable>(); // error C2760 unexpected token ')', expected 'expression'
    // ...
}

Если я попытаюсь использовать конструктор по умолчанию в этом методе, у меня будет упомянутая выше ошибка компиляции. Этот метод вызывается в производном классе, здесь:

// MyScene.cpp
#include "AScene.hpp"

void MyScene::initialize(void) {
    AScene::initialize_<Level>();
    // If I call root->addComponent<Scriptable>() directly here, its working perfectly
}

Вот реализация вариативного метода шаблона addComponent:

// AGameObject.hpp
template <typename C, typename ...Args>
void AGameObject::addComponent(Args&& ... args) {
    entity_.assign<C>(std::forward<Args>(args) ...);
}

Я не могу показать вам код assign(), поскольку он является частью библиотеки, но этот код всегда работает, если я не вызываю его в initialize_.

И вот мой класс Scriptable:

// Scriptable.hpp
struct Scriptable {
    Scriptable(void) = default;
    Scriptable(int i) {} // remember, used to bypass the default constructor
    // ...
};

На самом деле кажется, что компилятор просто игнорирует/не может найти конструктор по умолчанию, когда я вызываю метод addComponent в методе шаблона initialize_. Вы знаете, что я делаю неправильно?

Если вам нужна дополнительная информация, пожалуйста, сообщите мне.

ИЗМЕНИТЬ:

Я только что проверил реализацию assign() в библиотеке, и конструктор вызывается так:

C(std::forward<Args>(args) ...);

Вот ссылка, если вы хотите проверить это: https://github.com/alecthomas/entityx/blob/master/entityx/Entity.h#L648

Вот что мне компилятор говорит:

1>AGameObject.cpp 1>path\ascene.hpp(89): error C2760: syntax error: unexpected token ')', expected 'expression' 1>path\ascene.hpp(89): note: This diagnostic occurred in the compiler generated function 'void AScene::initialize_(void)'


person Stéphane G.    schedule 09.03.2019    source источник
comment
Вероятно, в частях ошибки компиляции, которые вы не показали, есть более важная информация. Код, который вы разместили, выглядит нормально, но, не зная, что делает assign, как вы можете ожидать здесь какой-либо помощи? Что касается кода, который вы показали, нет вызова конструктора Scriptable.   -  person super    schedule 09.03.2019
comment
Вы пробовали использовать Scriptable() = default вместо Scriptable(void) = default ?   -  person max66    schedule 09.03.2019
comment
@ max66 да, я пытался, и @super я отредактировал свой вопрос о том, что делает assign.   -  person Stéphane G.    schedule 09.03.2019
comment
я думаю, вам следует прочитать этот stackoverflow.com/questions/29879564/   -  person tinkertime    schedule 09.03.2019
comment
Спасибо за Ваш ответ. Я сделал. Самое странное в этой проблеме то, что я могу вызывать свою функцию без аргументов в методе, не являющемся шаблоном, так что проблема, я думаю, не в обработке с нулевым аргументом. Я также подумал, что это может быть проблема с циклическим включением, но по крайней мере с одним аргументом он может найти мой класс Scriptable.   -  person Stéphane G.    schedule 09.03.2019
comment
AScene.hpp отсутствует #include "AGameObject.hpp". Вот — mcve. Подсказка заключается в том, что компилятор понятия не имеет, что addComponent является шаблоном, поэтому он видит ((root->addComponent) < Scriptable) > () (т. е. < и > являются операторами "меньше" и "больше").   -  person Oktalist    schedule 09.03.2019
comment
Это было! Спасибо ! Я пробовал это, но было включение в AScene.hpp в AGameObject.hpp, что вызывало циклическое включение, и код взрывался. Теперь я просто помещаю все реализации шаблонов в файл .inl, и он отлично работает. Вы можете поместить этот комментарий в качестве ответа, я отмечу этот вопрос как ответ! Спасибо еще раз.   -  person Stéphane G.    schedule 09.03.2019


Ответы (1)


Я удивлен, что нет ответа на этот вопрос. Я столкнулся с той же проблемой, и я узнал, что это работает:

    root->addComponent<Scriptable>(3); // it works (3 is just a random value to bypass the default constructor, see below the Scriptable struct definition)
    root->addComponent<Scriptable>(); // error C2760 unexpected token ')', expected 'expression'
    root->template addComponent<Scriptable>(); //it works too

PS Это одна из тех причуд, которые я просто научился делать давным-давно, толком не понимая, зачем это нужно. Теория, стоящая за этим, объясняется здесь: Вызов функции шаблона в классе шаблона Но затем опять же, я не понимаю, почему вызовы с аргументами скомпилированы просто отлично. Так что, если кто-то может уточнить, я был бы признателен.

person Suslik    schedule 16.04.2020