1

I'm having a weird behavior concerning a template method calling a template variadic method and I can't find what's the problem. I'm using Visual Studio Community 2017.

The compile error is appearing in the following method :

// 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'
    // ...
}

If I try to use the default constructor in this method, I have the compile error mentionned above. This method is called in a derived class, here :

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

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

Here is the implementation of the addComponent template variadic method :

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

I can't show you the assign() code since it's part of a library, but this code is always working when I don't call it in the initialize_.

And here is my Scriptable class :

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

In fact, it seems that the compiler just ignore/can't find the default constructor when I'm calling the addComponent method in the template method initialize_. Do you know what I'm doing wrong ?

If you need further information, please tell me.

EDIT :

I just checked the assign() implementation in the library and the constructor is called like that :

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

Here is the link if you want to check it : https://github.com/alecthomas/entityx/blob/master/entityx/Entity.h#L648

Here is exactly what the compiler tell me :

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

Stéphane G.
  • 127
  • 1
  • 15
  • 1
    There is probably some more relevant information in parts of the compilation error that you haven't shown. The code you posted looks ok, but without knowing what `assign` does, how can you expect any help here? As far as the code you have showed there is no call to the constructor of `Scriptable`. – super Mar 09 '19 at 10:28
  • Have you tried with `Scriptable() = default` instead of `Scriptable(void) = default` ? – max66 Mar 09 '19 at 10:29
  • @max66 yes I have tried, and @super I have edited my question concerning what `assign` does. – Stéphane G. Mar 09 '19 at 10:47
  • i think you should read through this https://stackoverflow.com/questions/29879564/handling-zero-argument-variadic-template-in-c11 – tinkertime Mar 09 '19 at 15:25
  • Thanks for your answer. I did. The thing weird about this problem is that I can call my function without arguments in a non-template method, so the problem is not about handling with 0 argument, I guess. I also thought that it can be a cyclic includes problem but with at least one argument it can find my Scriptable class. – Stéphane G. Mar 09 '19 at 15:43
  • 1
    `AScene.hpp` is missing a `#include "AGameObject.hpp"`. [Here](https://godbolt.org/z/nmaBhf) is an mcve. The clue is that the compiler has no idea `addComponent` is a template, so it sees `((root->addComponent) < Scriptable) > ()` (i.e. `<` and `>` are less-than and greater-than operators). – Oktalist Mar 09 '19 at 18:40
  • That was it ! Thanks ! I had tried that but there was an include to the AScene.hpp in the AGameObject.hpp, which caused a cyclic inclusion and the code exploded so. Now I just put all the template implementations in a .inl file and it works great. You can put this comment as an answer I will mark this question answered ! Thanks again. – Stéphane G. Mar 09 '19 at 19:28

1 Answers1

0

I'm surprised to see there's no answer to this question. I have encountered the same problem and I found out that this works:

    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 This is one of those quirks that I just learned to do a long time ago without actually understanding why it's needed. The theory behind it is explained here: Calling template function within template class But then again, I don't understand why calls with arguments compiled just fine. So if somebody could elaborate, I'd be grateful.

Suslik
  • 73
  • 6