1

I know that the title sucks, it's just that I wasn't really sure how else to ask this, because I'm lacking knowledge in many basic C++ features and I'm trying to address them one by one.

So I'm starting to dive into C++ templates. For now I'm building really basic ones, simply to help me debug my code, like:

    void printVectors(const T& vec, const S& vec2) {
        for (int i = 0; i < vec.size(); i++) {
            print("------------");
            printNoEndln(vec[i]);
            printNoEndln("->");
            print(vec2[i]);
        }
    }

Now, starting with SDL, I came across something like this:

    template <typename T, typename... TArgs>
    T& AddComponent(TArgs&&... args) {
        T* newComponent(new T(std::forward<TArgs>(args)...));
        newComponent->componentName = typeid(T).name();
        newComponent->owner = this;
        components.emplace_back(newComponent);
        newComponent->Init();
        return *newComponent;
    }

So I'm going to describe what I understand by this line by line, and I'd be really glad if you guys could correct me.

1- Creating a template of type T with N arguments (Thats what the spread operator means here, right? It declares a variadic template?)

2- Declaring a function AddComponent that returns the reference of T and receiving N references of references of the type TArgs (???) (This part is really confusing to me).

3- Declaring a pointer T to a new object of type T in a very strange way. For starters, I don't understand why the instantiation of newComponent is being addressed with () such as newComponent() instead of T* newComponent = new Component(...)(Seriously, that is all that I can grasp from this line)

From line 4 and forward the code is very simple to me and needs no explanation whatsoever.

From what I could understand, my gap is not being able to understand: variadic templates and functions, rvalues, lvalues and the forward problem. Is that correct? Can you guys point me to useful articles regarding these topics? I find most of cpp references very formal and way beyond my league. It's funny how I can read C#, Java, Typescript and Javascript documentations with no problem but when it comes to C++ it gets really tough to extract something from the documentations. I usually just skip the formality to the actual example code and then I try it out myself on the compiler to understand what is happening.

I know it's a lot, answer with whatever information you judge useful.

Thanks guys

Bruno Giannotti
  • 323
  • 2
  • 13
  • 1
    https://stackoverflow.com/q/8526598/1870760 does this answer the `std::forward`? – Hatted Rooster Apr 15 '20 at 17:36
  • 1
    Check [this post](https://stackoverflow.com/questions/5481539/what-does-t-double-ampersand-mean-in-c11) for more information about declaring rvalue-references (`&&`) – melk Apr 15 '20 at 17:56

1 Answers1

1
template <typename T, typename... TArgs>
T& AddComponent(TArgs&&... args)

That's a declaration of a function template AddComponent. T and TArgs are template arguments, both of which must be types. TArgs is a variadic argument (can hold 0 or more types). A function template stamps out functions for each unique combination of T and TArgs, for ex. AddComponent<int,long,float> could be such a function.

TArgs&&... are called forwarding references because && inside a template declaration has an effect of preserving the value category (lvalue/rvalue) of the argument(s).

    T* newComponent(new T(std::forward<TArgs>(args)...));

That's a definition of a local variable newComponent of type pointer-to-T and initial value new T(std::forward<TArgs>(args)...).

std::forward is a helper utility that works together with TArgs&& and when needed passes rvalue references through to the call. When browsing code you can ignore it and read new T(std::forward<TArgs>(args)...) as new T(args...). Now that is a variadic pack expansion syntax; here the arguments args from the template are simply passed to new().

For more details refer to your favorite C++ Book. My favorite (years ago) was Effective Modern C++ by Scott Meyers (Scott calls forwarding references universal references, for the rest is a great book).

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • Thank you so much for the taking the time! Everything is almost cristal clear now! I just still can't understand this declaration of the local variable associated with the pointer-to-T. Why are we "calling" `newComponent` to define its initial value? Does this syntax only happens inside a template? I couldn't really reproduce it outside of the template scope. – Bruno Giannotti Apr 15 '20 at 21:14
  • 1
    That's direct initialization, the oldest syntax in C++. `int i(5);` is another example. It's not recommended because it can lead to the infamous most vexing parse. Modern C++ alternative syntax is `int i{5};` – rustyx Apr 15 '20 at 23:00