-1

Let's say I have this template class declared in my animal.hpp file:

enum class ANIMAL_TYPE{
     DOG,
     CAT,
};

template <ANIMAL_TYPE T>
class animal{
public:
    void makeSound();
    };

Pretty classic example used in explanations of interfaces and inheritance, but I want it to be known at compile time, and not be a virtual function, so I implemented it like this in the animal.cpp file:

template <>
class Animal<ANIMAL_TYPE::DOG>{
public:
    void makeSound(){
         std::cout << "woof";
    }
};

template <>
class Animal<ANIMAL_TYPE::CAT>{
public:
    void makeSound(){
         std::cout << "MEOW";
    }
};

template class Animal<ANIMAL_TYPE::DOG>;
template class Animal<ANIMAL_TYPE::CAT>;

And this in the main file:

#include <animal.hpp>


int main(){
    Animal<ANIMAL_TYPE::DOG> doggy;
    doggy.makeSound();
    return 0;
}

But when I compile and link this, I get an error during linking "undefined reference to Animal<(ANIMAL_TYPE)0>::makeSound"

  • It's really not clear why there's a template argument that's a enum vs. a proper derived class. This is unusual from an object-oriented design perspective. I'd argue this is *nowhere near* a classic example. If you want to do this properly, you do it via composition, in which case the sounds are from some other type that implements that. – tadman Jul 31 '23 at 14:58
  • 3
    Remember, template code needs to be in headers. It can't be in `.cpp` alone. This is one of the downsides to templates. What you're doing here is specializing the definition in a `.cpp` file, which doesn't do anything unless used, and then using it in another file which does not have those specializations defined. – tadman Jul 31 '23 at 15:00
  • How do you compile the code? Show the command that invokes the compiler. – 273K Jul 31 '23 at 15:00
  • @tadman the animal class is a classic exsample, not the way i did it. i used an enum as an exsample, but it might as well be anything else – urisig31414 Jul 31 '23 at 15:08
  • I'd argue it's not a great idea to go so orthogonal to conventional inheritance without a good reason. – tadman Jul 31 '23 at 15:08
  • Indeed the design is unclear. Yet you must start by making ```makeSound``` public and removing the explicit instanciation that are useless: https://godbolt.org/z/c1ezaajhr By the way, you have no inheritance at all in your example... Only full template specialization. – Oersted Jul 31 '23 at 15:09
  • @tadman: maybe the purpose of the exercise is to illustrate compile-time polymorphism? – Oersted Jul 31 '23 at 15:11
  • @273K g++ -c animal.cpp -o animal.o g++ -c main.cpp -o main.o g++ -c main.o animal.o -o animalTest – urisig31414 Jul 31 '23 at 15:12
  • @Oersted Perhaps, but confirmation required for such assumptions. – tadman Jul 31 '23 at 15:13
  • @urisig31414 see tadman comment about cpp files and templates. I think your link issue is there. – Oersted Jul 31 '23 at 15:14
  • functioning way of organizing your files: https://godbolt.org/z/o6WbqP6Ge – Oersted Jul 31 '23 at 15:19
  • @Oersted but im explicitly instantiating the templated classes here – urisig31414 Jul 31 '23 at 15:19
  • `template <> class Animal{ void makeSound(){ std::cout << "woof"; } };` -- this is useless, you specialize the class template, that is not available to main.cpp, but don't implement the class method. You might want `template <> void Animal::makeSound(){ std::cout << "woof"; }` – 273K Jul 31 '23 at 15:20
  • @273K thank you I think this is what I needed, what about having a second template argument? Something like this: ```template void Buffer::create(const std::vector &inputData, const Device &device, VkCommandPool commandPool)``` from code I use, but it doesn't compile, says template argument list must match the parameter list – urisig31414 Jul 31 '23 at 15:27

1 Answers1

0

Instead of instantiating the classes themselves, you should be instantiating the methods. In other words, instead of doing this:

template <>
class Animal<ANIMAL_TYPE::DOG>{
public:
    void makeSound(){
         std::cout << "woof";
    }
};

template <>
class Animal<ANIMAL_TYPE::CAT>{
public:
    void makeSound(){
         std::cout << "MEOW";
    }
};

You should be doing this:

template <>
void Animal<ANIMAL_TYPE::DOG>::makeSound()
{
    std::cout << "woof";
}

template <>
void Animal<ANIMAL_TYPE::CAT>::makeSound()
{
    std::cout << "MEOW";
}

Also, I've noticed that you have this at the bottom of animal.cpp.

template class Animal<ANIMAL_TYPE::DOG>;
template class Animal<ANIMAL_TYPE::CAT>;

Those have no effect in this case, you can just remove them.

EDIT: Okay, so if you want to have two template arguments, one of which is a type, and one that is not a type, you will need to directly instantiate the class, in the header because it's still a template, not a complete instantiation.

For example, let's say that the Animal class from before takes in a type argument.

template <ANIMAL_TYPE T, typename R>
class Animal{
    public:
    void makeSound(R foo);
};

You will have to instantiate it like this (Remember to put this in the header file, as it is still a template and not a complete instantiation).

template <typename R>
class Animal<ANIMAL_TYPE::DOG, R>{
    public:
    void makeSound(R foo)
    {
        std::cout << "woof";
    }
};

template <typename R>
class Animal<ANIMAL_TYPE::CAT, R>{
    public:
    void makeSound(R foo)
    {
        std::cout << "MEOW";
    }
};

Hopefully, this is helpful.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
w6tozM
  • 38
  • 1
  • 5
  • ive already asked this in another comment, but what if i want to have 2 arguemnts, and the implement my functions something like this: ```template void Buffer::create(const std::vector &inputData, const Device &device, VkCommandPool commandPool) ``` in this case i get a compiler error ```invalid use of incomplete type ‘class Buffer’``` buffer class:```template class Buffer{ /* declerations */ }``` – urisig31414 Jul 31 '23 at 15:42
  • @urisig31414 I've updated my answer. Hopefully, this is what you are looking for. – w6tozM Jul 31 '23 at 16:19
  • thank you, i forgot to approve your answer before but i approved it now – urisig31414 Aug 03 '23 at 11:49