0

I've been trying to forward declare a function who accepts template parameter, but when passing an derived class object it gives me

Error   LNK2019 unresolved external symbol 
"void __cdecl setSymetric<class Stars>(class std::vector<class Stars,class std::allocator<class Stars> > &,int,int,float,float)"
 (??$setSymetric@VStars@@@@YAXAEAV?$vector@VStars@@V?$allocator@VStars@@@std@@@std@@HHMM@Z) referenced in function 
"public: __cdecl Sector::Sector(class sf::RenderWindow &,class std::vector<class Window *,class std::allocator<class Window *> >,
class std::vector<class Image,class std::allocator<class Image> > const &)"
 (??0Sector@@QEAA@AEAVRenderWindow@sf@@V?$vector@PEAVWindow@@V?$allocator@PEAVWindow@@@std@@@std@@AEBV?$vector@VImage@@V?$allocator@VImage@@@std@@@4@@Z)        

But when I change the parameter with the base class it's working fine.

Here's my implementation of the function in my main.cpp:

template<typename A>
void setSymetric(std::vector<A>& buttons, const int startWidth,
    const int width, const float x, const float y)
{
    float substractedWidth = width - startWidth - (x * buttons.size());
    float deltaWidth = substractedWidth / (buttons.size() * 2);

    float currPos = startWidth;

    for (auto& k : buttons)
    {
        currPos += deltaWidth;

        k.getShape().setPosition(currPos, y);
        currPos += x + deltaWidth;
    }

}

Here's how I've forward declare it in my other file where I use it ( Sector.h it is an inline header ( I put my implementation and declaration there, but I'll separate them )

template<typename A>
extern void setSymetric(std::vector<A>& buttons, const int startWidth, const int width,
    const float x, const float y);

My base class:

#ifndef IMAGES
#define IMAGES

#include<string>
#include<iostream>

#include <SFML/Audio.hpp>
#include <SFML/Graphics.hpp>

const std::string ImagePath = "Content/";
const std::string AudioPath = "Sound/";

extern const double width;
extern const double height;

class Image
{
public:

    Image()
    {

    }
    void play()
    {
        this->player.play();
    }

    void setTexture(const std::string& texture)
    {
        if (!this->texture.loadFromFile(ImagePath + texture))
            std::cout << "problem \n";
        shape.setTexture(&this->texture);
        shape.setSize(sf::Vector2f((width + height) / 19, (width + height) / 19));
    }

    void setTexture(const sf::Texture& texture)
    {
        this->texture = texture;
    }

    sf::Texture& getTexture()
    {
        return this->texture;
    }

    void setSound(const std::string& sound)
    {
        this->sound.loadFromFile(AudioPath + sound);
        player.setBuffer(this->sound);
    }

    sf::RectangleShape& getShape()
    {
        return this->shape;
    }

    void setVisibility(const bool flag)
    {
        this->isVisible = flag;
        if (flag == false)
        {
            this->size = this->shape.getSize();
            shape.setSize(sf::Vector2f(0, 0));
        }
        else
            shape.setSize(this->size);
    }

protected:
    sf::Texture texture;
    sf::RectangleShape shape;

    bool isVisible = true;
    sf::Vector2f size;

    sf::SoundBuffer sound;
    sf::Sound player;
};

#endif

Here is the derived class I'm passing:

#pragma once

#include "Images.h"

class Stars : public Image
{
public:
    Stars() : Image() {

    }

    void activate() {
        this->setTexture("star.png");
    }
};

stars is two dimensional array with Stars data type. ( When it is Image it's working ) And here is how I am passing it:

setSymetric(stars[i], this->game[i].getShape().getPosition().x,
                this->game[i].getShape().getPosition().x + this->game[i].getShape().getSize().x,
                stars[i][0].getShape().getSize().x,
                this->game[i].getShape().getPosition().y + this->game[i].getShape().getSize().y);
  • 1
    Beware: templates are resolved at compile time, neither at run time nor link time. This is the reason why templated classes are generally fully defined in include files. If a part is only defined in a source .c files, not all template versions could be generated and you get a link error. – Serge Ballesta Feb 26 '21 at 15:17

1 Answers1

0

You have to explicitly instantiate the missing function and the constructor somewhere. So far you're only using them, i.e. referring to them, but no code you wrote causes the compiler to actually create instances of those types and emit them. Hence the error.

See e.g. this answer for more about explicit instantiation.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • Sorry I didn't really get why I am getting the error. Could you explain a little more about it ? Why I can't pass a derived class like that ? It works with Image object. – Ивелин Иванов Feb 26 '21 at 18:33