Home > Back-end >  Forward declaring a template type parameter
Forward declaring a template type parameter

Time:10-27

I see this question has been discussed in various places, e.g. here,here,here and here .But, i have still not been able to relate to the questions aforementioned.

My situation: I am trying to implement a simple generic visitor pattern in C . The hosts in this pattern are different pets, these are in a file called Pet.h. The visitors are in a separate header called Visitors.h.

The concrete Pet classes accept, generic visitor classes(See Comment 0 in Pet.h), and the generic visitor classes visits the generic Pet classes. So, there is a natural cyclic dependency.

Earlier, when all the code was in a single header, there were no problems. Now there is. To illustrate, here is the Pet.h class. P.S: I am using Visual Studio 2017.

#pragma once

#include <string>
#include "Visitors.h"


namespace pet
{
    class Pet {
    public:
        virtual ~Pet() {}
        virtual void accept(temp_visitor::PetVisitor& v) = 0; //Comment 0 Pet accepts a gneric PetVisitor
        virtual std::string getAnimal() = 0;
    private:
        std::string color_;
    };

    template <typename Derived>
    class Visitable : public Pet {
    public:
        using Pet::Pet;
        Visitable() = default;
        Visitable(const std::string& animal) : animal_(animal) {}
        void accept(temp_visitor::PetVisitor& v) override {
            v.visit(static_cast<Derived*>(this));  
        }

        std::string getAnimal() override
        {
            return animal_;
        }

        std::string animal_;
    };

    class Cat : public Visitable<Cat> {
        using Visitable<Cat>::Visitable;
    };

    class Dog : public Visitable<Dog> {
        using Visitable<Dog>::Visitable;
    };

}

And here is the Visitors.h file. The void visit(pet::Pet* p) gives the following error "use of undefined type pet::Pet on using p->getAnimal()

#include<iostream>

#pragma once

namespace pet
{
    class Pet; //Comment 1. Attempted forward declaration.
}

namespace temp_visitor
{
    template <typename ... Types>
    class Visitor;

    template <typename T>
    class Visitor<T> {
    public:
        virtual void visit(T* t) = 0;
    };

    using PetVisitor = Visitor<pet::Pet>;

    class FeedingVisitor : public PetVisitor {
    public:
        void visit(pet::Pet* p) override { std::cout << "Feed veggies to the "  p->getAnimal() << std::endl; }  //Comment 2: Gives the following error "use of undefined type pet::Pet"
    };
}

So how do i fix this problem ?

CodePudding user response:

You need to move the FeedingVisitor to a new header and cpp as well. In header you will have #include "Visitors.h", forward declration for Pet and in cpp #include "Pet.h"

Something like Visitors.hpp

namespace pet  {
    class Pet; //Comment 1. Attempted forward declaration.
}

namespace temp_visitor 
{
    template <typename ... Types>   class Visitor;

    template <typename T>  class Visitor<T> 
    {
    public:
        virtual void visit(T* t) = 0;
    };
}

FeedingVisitor.hpp

#include "Visitors.h"

namespace temp_visitor
{
    using PetVisitor = Visitor<pet::Pet>;

    class FeedingVisitor : public PetVisitor {
    public:
        void visit(pet::Pet* p) override;  // only declaration
    };
}

FeedingVisitor.cpp

// move the definition to cpp
void temp_visitor::FeedingVisitor::visit(pet::Pet* p) { 
   std::cout << "Feed veggies to the "   p->getAnimal() << std::endl; 
}
  • Related