Search code examples
c++templatesvisual-studio-2008dispatchvisitor-pattern

Using Templates to resolve virtual methods


This issue involves using templates to resolve virtual members in a Dispatch pattern.
Note: This is not the same as virtual template method questions already asked on StackOverflow. *

Edit 1: Corrected syntax errors, added clarifications.

Given the following:

#include <string>
#include <iostream>

class Field_Interface
{
  public:
    virtual std::string  get_field_name(void) const = 0;
};

class Field_Integer : public Field_Interface
{
  public:
    std::string get_field_name(void) const
    { return "INT";}
};

class Field_String : public Field_Interface
{
  public:
    std::string get_field_name(void) const
    { return "VARCHAR";}
};

class Field_Double : public Field_Interface
{
  public:
    std::string get_field_name(void) const
    { return "DOUBLE";}
};


class Abstract_Visitor
{
  public:
  virtual void visit(const Field_Integer& fi) = 0;
  virtual void visit(const Field_String& fi) = 0;
  virtual void visit(const Field_Double& fi) = 0;
};

class Visitor_Name_Query_1 : public Abstract_Visitor
{
  public:
  template <class Field>
  void visit(const Field& f)
  {
      std::cout << "Field name is: "
                << f.get_field_name()
                << "\n";
  }
};

class Visitor_Name_Query_2 : public Abstract_Visitor
{
  public:
    void visit(const Field_Integer& fi)
    { print_field_name(fi); }

    void visit(const Field_String& fi)
    { print_field_name(fi); }

    void visit(const Field_Double& fi)
    { print_field_name(fi); }

  private:
    void print_field_name(const Field_Interface& fi)
    { 
        std::cout << "Field name is: "
                  << fi.get_field_name()
                  << "\n";
    }
};

int main(void)
{
    Visitor_Name_Query_1    q1;
    Field_Integer           fi;
    q1.visit(f1);
    return 0;
}

The compiler is saying the templated method in Visitor_Name_Query_1 is not resolving the abstract interface from Abstract_Visitor.

Edit 2: Results from g++

# g++ -o main.exe main.cpp
main.cpp: In function `int main()':
main.cpp:75: error: cannot declare variable `q1' to be of type `Visitor_Name_Query_1'
main.cpp:75: error:   because the following virtual functions are abstract:
main.cpp:35: error:  virtual void Abstract_Visitor::visit(const Field_Integer&)
main.cpp:36: error:  virtual void Abstract_Visitor::visit(const Field_String&)
main.cpp:37: error:  virtual void Abstract_Visitor::visit(const Field_Double&)
main.cpp:77: error: `f1' undeclared (first use this function)
main.cpp:77: error: (Each undeclared identifier is reported only once for each function it appears in.)

Visitor_Name_Query_1 is an attempt to simplify the class Visitor_Name_Query_2. When the number of visit methods grows beyond a simple quantity (like 5), maintenance becomes tedious. This is the reason for the template declaration.

When the template is expanded, with one of the field types, the declaration matches the one in Visitor_Name_Query_2.

So why is the compiler generating saying that class Visitor_Name_Query_1 is abstract?

Note: I am using Visual Studio 2008 on Windows Vista.

* The other posts involve using templates to create virtual method declarations. I'm using templates to create functions that implement the abstract methods.


Solution

  • So why is the compiler generating saying that class Visitor_Name_Query_1 is abstract?

    Because the standard says so. §14.5.2 [temp.mem]/p4:

    A specialization of a member function template does not override a virtual function from a base class. [ Example:

    class B {
        virtual void f(int);
    };
    class D : public B {
        template <class T> void f(T); // does not override B::f(int)
        void f(int i) { f<>(i); }     // overriding function that calls
                                      // the template instantiation
    };
    

    end example ]