#How to initialize templated Class that depends on base class variable with a Derived class?

84 messages · Page 1 of 1 (latest)

left pelican
#

I'm trying to create a class that uses a variable from another class called Curve3, the problem is that I need to initialize this class using another class called LineCurve3 that inherits from Curve3, I'm trying to use template initialization of the class (TubeGeometry) but the compiler gives an error message: error LNK2019: unresolved external symbol, which I assume is because it tries to initialize the variable and call a function from the base class (Curve3) but because I initialize it with LineCurve3 it can't find them, is there a way to make this happen?

river vergeBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

clever knot
#

Also your description sounds like you're willingly options into object slicing, which almost always not what you actually want

left pelican
#
main.obj : error LNK2019: unresolved external symbol "public: static class std::shared_ptr<class graphics::TubeGeometry<class graphics::LineCurve3> > __cdecl graphics::TubeGeometry<class graphics::LineCurve3>::create(class std::shared_pt
r<class graphics::LineCurve3> const &,unsigned int,float,unsigned int,bool)" (?create@?$TubeGeometry@VLineCurve3@graphics@@@graphics@@SA?AV?$shared_ptr@V?$TubeGeometry@VLineCurve3@graphics@@@graphics@@@std@@AEBV?$shared_ptr@VLineCurve3@g
raphics@@@4@IMI_N@Z) referenced in function "__cdecl createTube(class graphics::Vector3 const &,class graphics::Color const &,class graphics::Vector3 const &,class graphics::Vector3 const &)" (?createTube@@YA@AEBVVector3@graphics@@AEBVCo 
lor@2@00@Z) [C:\Users\vitor\Documents\CODE\C++\gui_beginning_project\imgui_example\build\softvis.vcxproj]
left pelican
clever knot
#

Willingly opting

#

It was a typo

#

So you choose to use object slicing, and that's weird because object slicing is generally undesirable

#

And I'm asking if your certain that's what you want

#

Where is your template defined

#

Often templates rely on implicit instantiation to work, if you have that error then it suggests that in some way the template definition isn't accessible

left pelican
#

I don't know what object slicing is, but will look it up later,
the code is too big to put it here
variable initialization inside Tube geometry:

template <typename CurveType>
class TubeGeometry : public BufferGeometry {
...
Curve3::FrenetFrames frames;

initialization of class:

auto geometry = graphics::TubeGeometry<graphics::LineCurve3>::create(curve, 64, 1, 16, false);

function and variable from Curve3 used on TubeGeometry:

class Curve3 {
   public:
    int arcLengthDivisions{ 200 };

   public:
    struct FrenetFrames {
        std::vector<Vector3> tangents;
        std::vector<Vector3> normals;
        std::vector<Vector3> binormals;
    };

    FrenetFrames computeFrenetFrames(unsigned int segments, bool closed);
clever knot
#

So the simplest fix is to make it accessible

#

Let me clarify

left pelican
#

I was initializing the FrenetFrames variable before like this:

CurveType::FrenetFrames frames;

and it wasn't working also, this is the point of confusion, if I initialize TubeGeometry using LineCurve3, will TubeGeometry have access to the variable and function declared on Curve3 (they are public)?

clever knot
#

Somewhere you use TubeGeometry's static member function called create
Probably on that auto geometry = ... line

#

I'm asking where you've put the definition of create

#

In what file

#

Also is this the first time you're using templates?

left pelican
#

declaration:

static std::shared_ptr<TubeGeometry> create(
        const std::shared_ptr<CurveType>& path,
        unsigned int tubularSegments = 64,
        float radius = 1,
        unsigned int radialSegments = 16,
        bool closed = false);

definition:

template <typename CurveType>
std::shared_ptr<TubeGeometry<CurveType>> TubeGeometry<CurveType>::create(const std::shared_ptr<CurveType>& path, unsigned int tubularSegments, float radius, unsigned int radialSegments, bool closed) {
    return create(path, Params(tubularSegments, radius, radialSegments, closed));
}
clever knot
#

The file

#

Where are those things

left pelican
clever knot
#

In what file(s)

left pelican
#

on tube geometry files

earnest turtle
left pelican
#

declaration on .hpp, definition on .cpp

#

I'm linking with cmake, I think there is a low chance this is the issue

earnest turtle
#

Prefereable inline in the class

#

The compiler needs to be able to see the whole definition at compile time

left pelican
#

so all the functions have to be on the header?

earnest turtle
#

By define them in the class definition I mean like this```cpp
template<class T>
class foo
{
public:
void bar()
{
}
};

left pelican
#

I don't think this is the issue

#

there is another class that uses templates and it was done the same way this class I'm trying to change now and it was compiling fine

clever knot
left pelican
#

this class (TubeGeometry) that I'm trying to change now was supposed to work only with Curve3, but I need it to work with LineCurve3, this is why I changed to a template initialization

clever knot
#

I'll leave it to grumpy to explain because I need to go

earnest turtle
#

You need to put the defintions in the header file simple as. It might compile because either A you are using the definitions in the same cpp file, B nothing is actually referencing these functions or C you have specialized templates so the definitions are compiled somewhere.

#

But as a rule always put the full definitions for a templated class in the header file. It will work, I'm pretty sure

left pelican
#

I will try it, so any class that uses templates I should put all the function definitions on the header along with the declarations?

earnest turtle
#

It will save you a bunch of typing too

left pelican
#

do you know where can I read more about this concept? It was hard to come up with search terms to clarify this

earnest turtle
#

A template isn't really a class, it's a blueprint in which the compiler can stamp out classes. Templates don't really exist until you instantiate one. So when you do instantiate it you get a whole new version of all the methods too. These methods have different signatures and as a result you can't really have one shared definition because the signatures wouldn't match (unless you specialise the template). As a result you also need to provide a defintion for the compiler to see to go along with the decleration signature. The easiest way to do that is to define it inside the class

#

;asm ```cpp
template <class T>
T foo(){return T{};}

main bobcatBOT
#
Compilation successful

No assembly generated.

earnest turtle
#

^^ see like this the compile produces no code for it at all

#

;asm```cpp
template <class T>
T foo(){return T{};}

int bar(){return foo<int>();}

main bobcatBOT
#
Assembly Output
bar():
  push rbp
  mov rbp, rsp
  call int foo<int>()
  pop rbp
  ret
int foo<int>():
  push rbp
  mov rbp, rsp
  mov eax, 0
  pop rbp
  ret

earnest turtle
# main bobcat

See how now there is an instanciation a version of that function is made

left pelican
# earnest turtle I mean if you need something to back it up then here https://stackoverflow.com/q...

It's not that I need something to back it up, I just want to learn more, it was hard to come up with terms/keywords to search for...I've also read somewhere that including definitions on headers leads to code bloat because multiple copies of the same function are included in different translation units and also can lead to increase in compilation time, so I'm trying to clarify from first principles the points of confusion

earnest turtle
#

The whole idea in templates is lieterally "I'm gonna get the compiler to do work for me" in which case that takes time

left pelican
#

hmm that's sad, this shit breaks my head man kkkkk

#

I will try to come up with other solutions then, do you recommend avoiding templates whenever possible?

earnest turtle
#

I wouldn't worry about it. It will not slow down you compile times by any human measurable amount unless you're instantiating thousands of objects

#

I would not recommend avoiding them. Templates are a massive part of C++ and an extremely powerful tool

left pelican
earnest turtle
#

It won't make any significant difference

left pelican
#

thank you for taking the time to help! I will try this solution and read more about the topics you shared

river vergeBOT
#

@left pelican Has your question been resolved? If so, type !solved :)

left pelican
#

I've changed TubeGeometry to have function definition instead of declaration and still getting the same error

earnest turtle
#

And send the code for what you did

left pelican
#

I think I understand what the problem is now and is because of what you said: "A template isn't really a class, it's a blueprint in which the compiler can stamp out classes. Templates don't really exist until you instantiate one", the function I'm using to create the class is a static function, if I put the function definitions on the header and change to static inline it also gives the same error from before, but if I remove the static it gives another error indicating I have to change the way I'm initializing the class, so my guess is the error is not because of the Curve3 variable, it's because I'm trying to initialize a templated class using a static function, but not sure

#

I did what you recommended and put all the function definitions inside of the header inside of the class declaration and removed the .cpp file from the compilation process, then changed some of the definitions that had static before and added inline, so static inline, same error from before...I'm thinking about how to change the class so it doesn't rely on static functions on initialization and will try that next

left pelican
#

I initialized the class like this:

std::shared_ptr<graphics::LineCurve3> curve = std::make_shared<graphics::LineCurve3>(from, to);
auto geometry = graphics::TubeGeometry::create(curve, 64, 1, 16, false);

and changed the TubeGeometry to work with a Curve3 type instead of making it template based, and it seems somehow this works...not sure why though

#

!solved

river vergeBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity

clever knot
#

but it can lead to duplication and "bloat" across the TUs

#

and yes that means the compiler does the same job multiple time, but in many cases it doesn't matter

#

in the end the TUs will be merged into a final program and the duplication is kicked out

#

that's if we're talking about making one program, this starts getting more complicated if you start accounting for libraries

#

but usually you'd first ensure your construct is correct, and in most common use cases for templates that means putting the definition in the header

#

worry about optimizing the binary content after, when you're more familiar with all the toolchain/stack

#

you'll still have a lot to learn about just regular language construct and how they work

#

and also whether it's really impactful on your perf (compile/run time, memory, binary size, etc...)

left pelican
#

templates combined with class inheritance broke my brain, specially when thinking about memory and class instances, so far it has been the hardest thing to get used to