Static Polymorphism with boost variant single visitor vs multi visitor vs dynamic polymorphism : <p>I am comparing the performance of the following methods of C++ Polymorphism:</p>

<p>Method [1]. static polymorphism using boost variants with a separate visitor for each method
Method [2]. static polymorphism using boost variants with a single visitor that calls different method using method overloading
Method [3]. Plain old dynamic polymorphism</p>

<p>Platform:
- Intel x86 64 bit Red Hat modern multi-core processor, 32 GB RAM
- gcc (GCC) 4.8.1 with -O2 optimization
- Boost 1.6.0</p>

<p>Some findings:</p>

<ul>
<li>Method [1] seems to have significantly outperform Methods [2] and [3]</li>
<li>Method [3] outperforms Method [2] most of the time</li>
</ul>

<p>My question is, why does Method [2] where I am using a visitor but using method overloading to call the correct method give worse performance than virtual methods. I would expect static polymorphism to fare better than dynamic polymorphism. I understand there is some cost of the extra parameter that is being passed in method [2] to figure which visit() method of the class to call and possibly some more branching due to method overloading? But shouldn"t this still outperform virtual methods?</p>

<p>Code is below:</p>

<pre><code>// qcpptest.hpp

#ifndef INCLUDED_QCPPTEST_H
#define INCLUDED_QCPPTEST_H

#include &lt;boost/variant.hpp&gt;

class IShape {
 public:
  virtual void rotate() = 0;
  virtual void spin() = 0;
};

class Square : public IShape {
 public:
  void rotate() {
   // std::cout &lt;&lt; "Square:I am rotating" &lt;&lt; std::endl;
    }
  void spin() { 
    // std::cout &lt;&lt; "Square:I am spinning" &lt;&lt; std::endl; 
  }
};

class Circle : public IShape {
 public:
  void rotate() { 
    // std::cout &lt;&lt; "Circle:I am rotating" &lt;&lt; std::endl; 
  }
  void spin() {
   // std::cout &lt;&lt; "Circle:I am spinning" &lt;&lt; std::endl; 
}
};

// template variation

// enum class M {ADD, DEL};
struct ADD {};
struct DEL {};

class TSquare {
    int i;
 public:
    void visit(const ADD&amp; add) {
        this-&gt;i++;
    // std::cout &lt;&lt; "TSquare:I am rotating" &lt;&lt; std::endl;
  }
    void visit(const DEL&amp; del) {
        this-&gt;i++;
    // std::cout &lt;&lt; "TSquare:I am spinning" &lt;&lt; std::endl;
  }

    void spin() {
        this-&gt;i++;
     // std::cout &lt;&lt; "TSquare:I am rotating" &lt;&lt; std::endl; 
 }
    void rotate() {
        this-&gt;i++;
     // std::cout &lt;&lt; "TSquare:I am spinning" &lt;&lt; std::endl; 
 }
};

class TCircle {
    int i;
 public:
    void visit(const ADD&amp; add) {
        this-&gt;i++;
    // std::cout &lt;&lt; "TCircle:I am rotating" &lt;&lt; std::endl;
  }
    void visit(const DEL&amp; del) {
        this-&gt;i++;
    // std::cout &lt;&lt; "TCircle:I am spinning" &lt;&lt; std::endl;
  }
    void spin() { 
        this-&gt;i++;
        // std::cout &lt;&lt; "TSquare:I am rotating" &lt;&lt; std::endl; 
    }
    void rotate() {
    this-&gt;i++; 
        // std::cout &lt;&lt; "TSquare:I am spinning" &lt;&lt; std::endl; 
    }
};

class MultiVisitor : public boost::static_visitor&lt;void&gt; {
 public:
  template &lt;typename T, typename U&gt;

    void operator()(T&amp; t, const U&amp; u) {
    // std::cout &lt;&lt; "visit" &lt;&lt; std::endl;
    t.visit(u);
  }
};

// separate visitors, single dispatch

class RotateVisitor : public boost::static_visitor&lt;void&gt; {
 public:
  template &lt;class T&gt;
  void operator()(T&amp; x) {
    x.rotate();
  }
};

class SpinVisitor : public boost::static_visitor&lt;void&gt; {
 public:
  template &lt;class T&gt;
  void operator()(T&amp; x) {
    x.spin();
  }
};

#endif

// qcpptest.cpp

#include &lt;iostream&gt;
#include "qcpptest.hpp"
#include &lt;vector&gt;
#include &lt;boost/chrono.hpp&gt;

using MV = boost::variant&lt;ADD, DEL&gt;;
// MV const add = M::ADD;
// MV const del = M::DEL;
static MV const add = ADD();
static MV const del = DEL();

void make_virtual_shapes(int iters) {
  // std::cout &lt;&lt; "make_virtual_shapes" &lt;&lt; std::endl;
  std::vector&lt;IShape*&gt; shapes;
  shapes.push_back(new Square());
  shapes.push_back(new Circle());

  boost::chrono::high_resolution_clock::time_point start =
      boost::chrono::high_resolution_clock::now();

  for (int i = 0; i &lt; iters; i++) {
    for (IShape* shape : shapes) {
      shape-&gt;rotate();
      shape-&gt;spin();
    }
  }

  boost::chrono::nanoseconds nanos =
      boost::chrono::high_resolution_clock::now() - start;
  std::cout &lt;&lt; "make_virtual_shapes took " &lt;&lt; nanos.count() * 1e-6
            &lt;&lt; " millis\n";
}

void make_template_shapes(int iters) {
  // std::cout &lt;&lt; "make_template_shapes" &lt;&lt; std::endl;
  using TShapes = boost::variant&lt;TSquare, TCircle&gt;;
  // using MV = boost::variant&lt; M &gt;;

  // xyz
  std::vector&lt;TShapes&gt; tshapes;
  tshapes.push_back(TSquare());
  tshapes.push_back(TCircle());
  MultiVisitor mv;

  boost::chrono::high_resolution_clock::time_point start =
      boost::chrono::high_resolution_clock::now();

  for (int i = 0; i &lt; iters; i++) {
    for (TShapes&amp; shape : tshapes) {
      boost::apply_visitor(mv, shape, add);
      boost::apply_visitor(mv, shape, del);
      // boost::apply_visitor(sv, shape);
    }
  }
  boost::chrono::nanoseconds nanos =
      boost::chrono::high_resolution_clock::now() - start;
  std::cout &lt;&lt; "make_template_shapes took " &lt;&lt; nanos.count() * 1e-6
            &lt;&lt; " millis\n";
}

void make_template_shapes_single(int iters) {
  // std::cout &lt;&lt; "make_template_shapes_single" &lt;&lt; std::endl;
  using TShapes = boost::variant&lt;TSquare, TCircle&gt;;
  // xyz
  std::vector&lt;TShapes&gt; tshapes;
  tshapes.push_back(TSquare());
  tshapes.push_back(TCircle());
  SpinVisitor sv;
  RotateVisitor rv;

  boost::chrono::high_resolution_clock::time_point start =
      boost::chrono::high_resolution_clock::now();

  for (int i = 0; i &lt; iters; i++) {
    for (TShapes&amp; shape : tshapes) {
      boost::apply_visitor(rv, shape);
      boost::apply_visitor(sv, shape);
    }
  }
  boost::chrono::nanoseconds nanos =
      boost::chrono::high_resolution_clock::now() - start;
  std::cout &lt;&lt; "make_template_shapes_single took " &lt;&lt; nanos.count() * 1e-6
            &lt;&lt; " millis\n";
}

int main(int argc, const char* argv[]) {
  std::cout &lt;&lt; "Hello, cmake" &lt;&lt; std::endl;

  int iters = atoi(argv[1]);

  make_virtual_shapes(iters);
  make_template_shapes(iters);
  make_template_shapes_single(iters);

  return 0;
}
</code></pre>
