diff --git a/Tracking/Acts/ActsTrackReconstruction/src/ITrackStatePrinter.h b/Tracking/Acts/ActsTrackReconstruction/src/ITrackStatePrinter.h
deleted file mode 100644
index 13e68ce0df05aa4f9fee781fa64cd17da000c832..0000000000000000000000000000000000000000
--- a/Tracking/Acts/ActsTrackReconstruction/src/ITrackStatePrinter.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
-*/
-
-#ifndef ACTSTRKFINDINGTOOL_ITRACKSTATEPRINTER_H
-#define ACTSTRKFINDINGTOOL_ITRACKSTATEPRINTER_H 1
-
-// Base
-#include "GaudiKernel/IAlgTool.h"
-
-// ATHENA
-#include "GeoPrimitives/GeoPrimitives.h"
-#include "GaudiKernel/EventContext.h"
-
-// ACTS CORE
-#include "Acts/Geometry/TrackingGeometry.hpp"
-#include "Acts/EventData/TrackParameters.hpp"
-
-// PACKAGE
-#include "ActsGeometry/ATLASSourceLink.h"
-#include "ActsEvent/Seed.h"
-#include "ActsEvent/TrackContainer.h"
-
-// Other
-#include <vector>
-namespace InDetDD
-{
-  class SiDetectorElementCollection;
-}
-namespace ActsTrk
-{
-  class ITrackStatePrinter
-      : virtual public IAlgTool
-  {
-  public:
-    DeclareInterfaceID(ITrackStatePrinter, 1, 0);
-
-    virtual void
-    printMeasurements(const EventContext &ctx,
-                      const std::vector<const xAOD::UncalibratedMeasurementContainer *> &clusterContainers,
-                      const std::vector<const InDetDD::SiDetectorElementCollection *> &detectorElementCollections,
-                      const std::vector<size_t> &offsets) const = 0;
-
-    virtual void
-    printSeed(const Acts::GeometryContext &tgContext,
-              const ActsTrk::Seed &seed,
-              const Acts::BoundTrackParameters &initialParameters,
-              size_t measurementOffset,
-              size_t iseed,
-              bool isKF) const = 0;
-
-    virtual void
-    printTrack(const Acts::GeometryContext &tgContext,
-               const ActsTrk::MutableTrackContainer &tracks,
-               const ActsTrk::MutableTrackContainer::TrackProxy &track,
-               const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &offset) const = 0;
-
-    virtual void
-    printTrackState(const Acts::GeometryContext &tgContext,
-                    const ActsTrk::MutableTrackStateBackend::ConstTrackStateProxy &state,
-                    const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &container_offset,
-                    bool useFiltered = false) const = 0;
-  };
-
-} // namespace
-
-#endif
diff --git a/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.cxx b/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.cxx
index 0a4717af2aa0291826a6652b477a68cb9a420d97..f8ad5f93098ddc6c84afa42249b3b32dee461273 100644
--- a/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.cxx
+++ b/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 #include "src/TrackFindingAlg.h"
 #include "src/TrackFindingData.h"
diff --git a/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.h b/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.h
index 539f08481dfe8fffa9ead5753b554658088396b7..b281ae0034e1ba1e514025e339bdab77556064b6 100644
--- a/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.h
+++ b/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingAlg.h
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 #ifndef ACTSTRACKRECONSTRUCTION_TRACKFINDINGALG_H
@@ -14,7 +14,7 @@
 // Tools
 #include "ActsGeometryInterfaces/IActsExtrapolationTool.h"
 #include "ActsGeometryInterfaces/IActsTrackingGeometryTool.h"
-#include "src/ITrackStatePrinter.h"
+#include "src/TrackStatePrinter.h"
 
 // ACTS
 #include "ActsEvent/Seed.h"
@@ -75,7 +75,7 @@ namespace ActsTrk
     ToolHandle<IActsExtrapolationTool> m_extrapolationTool{this, "ExtrapolationTool", ""};
     ToolHandle<IActsTrackingGeometryTool> m_trackingGeometryTool{this, "TrackingGeometryTool", ""};
     ToolHandle<ActsTrk::IActsToTrkConverterTool> m_ATLASConverterTool{this, "ATLASConverterTool", ""};
-    ToolHandle<ActsTrk::ITrackStatePrinter> m_trackStatePrinter{this, "TrackStatePrinter", "", "optional track state printer"};
+    ToolHandle<ActsTrk::TrackStatePrinter> m_trackStatePrinter{this, "TrackStatePrinter", "", "optional track state printer"};
     ToolHandle<ActsTrk::IFitterTool> m_fitterTool{this, "FitterTool", "", "Fitter Tool for Seeds"};
     ToolHandle<ActsTrk::IOnTrackCalibratorTool<ActsTrk::MutableTrackStateBackend>> m_pixelCalibTool{
       this, "PixelCalibrator", "", "Opt. pixel measurement calibrator"};
diff --git a/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingData.h b/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingData.h
index e492ffe719cf796b1a2e7c9aceb477a9f82e9c50..48694c08cf3815d6e79f9a11bde7e002b270fe10 100644
--- a/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingData.h
+++ b/Tracking/Acts/ActsTrackReconstruction/src/TrackFindingData.h
@@ -23,7 +23,7 @@
 #include "ActsGeometry/ATLASSourceLink.h"
 #include "ActsGeometry/TrackingSurfaceHelper.h"
 #include "ActsEventCnv/IActsToTrkConverterTool.h"
-#include "src/ITrackStatePrinter.h"
+#include "src/TrackStatePrinter.h"
 
 #include <unordered_map>
 #include <utility>
diff --git a/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.cxx b/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.cxx
index ca87b50747aa74d2dd0f96ccd738a216878b22c6..9f36555926a9632c175b11dcdc080c8f874b448b 100644
--- a/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.cxx
+++ b/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.cxx
@@ -1,5 +1,5 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
 #include "src/TrackStatePrinter.h"
@@ -7,6 +7,7 @@
 // Athena
 #include "TrkParameters/TrackParameters.h"
 #include "InDetReadoutGeometry/SiDetectorElementCollection.h"
+#include "xAODMeasurementBase/UncalibratedMeasurementContainer.h"
 
 // ACTS
 #include "Acts/Definitions/Units.hpp"
@@ -18,34 +19,24 @@
 #include "Acts/Surfaces/DiscSurface.hpp"
 #include "Acts/EventData/TransformationHelpers.hpp"
 
-#include "ActsEvent/TrackContainer.h"
-
 // PACKAGE
 #include "ActsGeometry/ActsDetectorElement.h"
+#include "ActsEvent/TrackContainer.h"
 #include "ActsInterop/Logger.h"
 
 // Other
+#include <vector>
+#include <iostream>
 #include <sstream>
 
 namespace ActsTrk
 {
   /// =========================================================================
-  /// Debug printout routines
-  /// This is only required by code in this file, so we keep it in the anonymous namespace.
-  /// The actual TrackStatePrinter class definition comes later.
+  /// file-local static functions and static TrackStatePrinter member functions.
+  /// TrackStatePrinter class method definitions comes later.
   /// =========================================================================
 
-  /// format all arguments and return as a string.
-  /// Used here to apply std::setw() to the combination of values.
-  template <typename... Types>
-  static std::string to_string(Types &&...values)
-  {
-    std::ostringstream os;
-    (os << ... << values);
-    return os.str();
-  }
-
-  static std::string trackStateName(Acts::ConstTrackStateType trackStateType)
+  std::string TrackStatePrinter::trackStateName(Acts::ConstTrackStateType trackStateType)
   {
     static constexpr std::array<std::tuple<bool, Acts::TrackStateFlag, char>, 6> trackStateNames{{
         {false, Acts::TrackStateFlag::ParameterFlag, '-'},
@@ -65,7 +56,7 @@ namespace ActsTrk
   }
 
   // compact surface/boundary name
-  static std::string actsSurfaceName(const Acts::Surface &surface)
+  std::string TrackStatePrinter::actsSurfaceName(const Acts::Surface &surface)
   {
     std::string name = surface.name();
     if (name.compare(0, 6, "Acts::") == 0)
@@ -394,7 +385,7 @@ namespace ActsTrk
     std::cout << '\n';
   }
 
-  static void printParameters(const Acts::Surface &surface, const Acts::GeometryContext &tgContext, const Acts::BoundVector &bound)
+  void TrackStatePrinter::printParameters(const Acts::Surface &surface, const Acts::GeometryContext &tgContext, const Acts::BoundVector &bound)
   {
     auto p = Acts::transformBoundToFreeParameters(surface, tgContext, bound);
     std::cout << std::fixed
@@ -409,15 +400,14 @@ namespace ActsTrk
               << std::defaultfloat << std::setprecision(-1);
   }
 
-} // anonymous namespace
+  /// =========================================================================
+  /// TrackStatePrinter class method definitions
+  /// =========================================================================
 
-/// =========================================================================
-namespace ActsTrk
-{
   TrackStatePrinter::TrackStatePrinter(const std::string &type,
                                        const std::string &name,
                                        const IInterface *parent)
-      : base_class(type, name, parent)
+      : AthAlgTool(type, name, parent)
   {
   }
 
@@ -474,126 +464,6 @@ namespace ActsTrk
               << std::flush;
   }
 
-  void
-  TrackStatePrinter::printTrack(const Acts::GeometryContext &tgContext,
-                                 const ActsTrk::MutableTrackContainer &tracks,
-                                 const ActsTrk::MutableTrackContainer::TrackProxy &track,
-                                 const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &container_offset) const
-  {
-    const auto lastMeasurementIndex = track.tipIndex();
-    // to print track states from inside outward, we need to reverse the order of visitBackwards().
-    std::vector<ActsTrk::MutableTrackStateBackend::ConstTrackStateProxy> states;
-    states.reserve(lastMeasurementIndex + 1); // could be an overestimate
-    size_t npixel = 0, nstrip = 0;
-    tracks.trackStateContainer().visitBackwards(
-        lastMeasurementIndex,
-        [&states, &npixel, &nstrip](const ActsTrk::MutableTrackStateBackend::ConstTrackStateProxy &state) -> void
-        {
-          if (state.hasCalibrated())
-          {
-            if (state.calibratedSize() == 1)
-              ++nstrip;
-            else if (state.calibratedSize() == 2)
-              ++npixel;
-          }
-          states.push_back(state);
-        });
-
-    if (track.nMeasurements() + track.nOutliers() != npixel + nstrip)
-    {
-      ATH_MSG_WARNING("Track has " << track.nMeasurements() + track.nOutliers() << " measurements + outliers, but "
-                                    << npixel + nstrip << " pixel + strip hits");
-    }
-
-    const Acts::BoundTrackParameters per(track.referenceSurface().getSharedPtr(),
-                                          track.parameters(),
-                                          track.covariance(),
-                                          track.particleHypothesis());
-    std::cout << std::setw(5) << lastMeasurementIndex << ' '
-              << std::left
-              << std::setw(4) << "parm" << ' '
-              << std::setw(21) << actsSurfaceName(per.referenceSurface()) << ' '
-              << std::setw(22) << to_string("#hit=", npixel, '/', nstrip, ", #hole=", track.nHoles()) << ' '
-              << std::right;
-    printParameters(per.referenceSurface(), tgContext, per.parameters());
-    std::cout << std::fixed << std::setw(8) << ' '
-              << std::setw(7) << std::setprecision(1) << track.chi2() << ' '
-              << std::left
-              << "#out=" << track.nOutliers()
-              << ", #sh=" << track.nSharedHits()
-              << std::right << std::defaultfloat << std::setprecision(-1) << '\n';
-
-    for (auto i = states.size(); i > 0;)
-    {
-      printTrackState(tgContext, states[--i], container_offset);
-    }
-  }
-
-  void
-  TrackStatePrinter::printTrackState(const Acts::GeometryContext &tgContext,
-                                     const ActsTrk::MutableTrackStateBackend::ConstTrackStateProxy &state,
-                                     const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &container_offset,
-                                     bool useFiltered) const
-  {
-    if (!m_printFilteredStates && useFiltered)
-      return;
-
-    ptrdiff_t index = -1;
-
-    if (state.hasUncalibratedSourceLink())
-    {
-      ATLASUncalibSourceLink sl = state.getUncalibratedSourceLink().template get<ATLASUncalibSourceLink>();
-      index = (*sl)->index();
-      for (const auto &[container, offset] : container_offset)
-      {
-        if ((*sl)->container() == container)
-        {
-          index += offset;
-          break;
-        }
-      }
-    }
-
-    std::cout << std::setw(5) << state.index() << ' ';
-    char ptype = !m_printFilteredStates ? ' '
-                 : useFiltered          ? 'F'
-                                        : 'S';
-    if (state.hasCalibrated())
-    {
-      std::cout << ptype << std::setw(2) << state.calibratedSize() << 'D';
-    }
-    else if (state.typeFlags().test(Acts::TrackStateFlag::HoleFlag))
-    {
-      std::cout << std::setw(4) << "hole";
-    }
-    else
-    {
-      std::cout << ptype << std::setw(3) << " ";
-    }
-    std::cout << ' '
-              << std::left
-              << std::setw(21) << actsSurfaceName(state.referenceSurface()) << ' ';
-    if (index >= 0)
-    {
-      std::cout << std::setw(22) << index << ' ';
-    }
-    else
-    {
-      std::cout << std::setw(22) << to_string(state.referenceSurface().geometryId()) << ' ';
-    }
-    std::cout << std::right;
-    const auto &parameters = !useFiltered          ? state.parameters()
-                             : state.hasFiltered() ? state.filtered()
-                                                   : state.predicted();
-    printParameters(state.referenceSurface(), tgContext, parameters);
-    std::cout << ' '
-              << std::fixed
-              << std::setw(6) << std::setprecision(1) << state.pathLength() << ' '
-              << std::setw(7) << std::setprecision(1) << state.chi2() << ' '
-              << std::defaultfloat << std::setprecision(-1)
-              << std::setw(Acts::TrackStateFlag::NumTrackStateFlags) << trackStateName(state.typeFlags()) << '\n';
-  }
-
   void
   TrackStatePrinter::printMeasurements(const EventContext &ctx,
                                        const std::vector<const xAOD::UncalibratedMeasurementContainer *> &clusterContainers,
diff --git a/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.h b/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.h
index d099d58608c7d37a43aa920d563def867263d5a0..1879ae5859de01c805ce94dcf41ce664db94e6da 100644
--- a/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.h
+++ b/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.h
@@ -1,32 +1,45 @@
 /*
-  Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
 */
 
-#ifndef ACTSTRKFINDINGTOOL_TRACKSTATEPRINTER_H
-#define ACTSTRKFINDINGTOOL_TRACKSTATEPRINTER_H 1
+#ifndef ACTSTRACKRECONSTRUCTION_TRACKSTATEPRINTER_H
+#define ACTSTRACKRECONSTRUCTION_TRACKSTATEPRINTER_H 1
 
 // Base
-#include "src/ITrackStatePrinter.h"
 #include "AthenaBaseComps/AthAlgTool.h"
 
 // ATHENA
+#include "GeoPrimitives/GeoPrimitives.h"
+#include "GaudiKernel/EventContext.h"
 #include "StoreGate/ReadHandleKeyArray.h"
 #include "xAODInDetMeasurement/SpacePoint.h"
+#include "xAODMeasurementBase/UncalibratedMeasurementContainer.h"
 
 // ACTS CORE
 #include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/EventData/TrackParameters.hpp"
+#include "Acts/EventData/TrackStateType.hpp"
 
 // PACKAGE
+#include "ActsGeometry/ATLASSourceLink.h"
+#include "ActsEvent/Seed.h"
+#include "ActsEvent/TrackContainer.h"
 #include "ActsGeometryInterfaces/ActsGeometryContext.h"
 #include "ActsGeometryInterfaces/IActsTrackingGeometryTool.h"
 #include "xAODInDetMeasurement/SpacePointContainer.h"
 #include "ActsEventCnv/IActsToTrkConverterTool.h"
 
 // Other
+#include <vector>
 #include <memory>
 #include <tuple>
 #include <boost/container/small_vector.hpp>
 
+namespace Acts
+{
+  class Surface;
+}
+
 namespace InDetDD
 {
   class SiDetectorElementCollection;
@@ -34,7 +47,7 @@ namespace InDetDD
 
 namespace ActsTrk
 {
-  class TrackStatePrinter : public extends<AthAlgTool, ActsTrk::ITrackStatePrinter>
+  class TrackStatePrinter : virtual public AthAlgTool
   {
   public:
     TrackStatePrinter(const std::string &type, const std::string &name,
@@ -48,7 +61,7 @@ namespace ActsTrk
     printMeasurements(const EventContext &ctx,
                       const std::vector<const xAOD::UncalibratedMeasurementContainer *> &clusterContainers,
                       const std::vector<const InDetDD::SiDetectorElementCollection *> &detectorElementCollections,
-                      const std::vector<size_t> &offsets) const override;
+                      const std::vector<size_t> &offsets) const;
 
     void
     printSeed(const Acts::GeometryContext &tgContext,
@@ -56,19 +69,21 @@ namespace ActsTrk
               const Acts::BoundTrackParameters &initialParameters,
               size_t measurementOffset,
               size_t iseed,
-              bool isKF) const override;
+              bool isKF) const;
 
+    template <typename track_container_t>
     void
     printTrack(const Acts::GeometryContext &tgContext,
-               const ActsTrk::MutableTrackContainer &tracks,
-               const ActsTrk::MutableTrackContainer::TrackProxy &track,
-               const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &offset) const override;
+               const track_container_t &tracks,
+               const typename track_container_t::TrackProxy &track,
+               const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &offset) const;
 
+    template <typename track_state_proxy_t>
     void
     printTrackState(const Acts::GeometryContext &tgContext,
-                    const ActsTrk::MutableTrackStateBackend::ConstTrackStateProxy &state,
+                    const track_state_proxy_t &state,
                     const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &container_offset,
-                    bool useFiltered = false) const override;
+                    bool useFiltered = false) const;
 
     using MeasurementInfo = std::tuple<size_t,
                                        const ATLASUncalibSourceLink *,
@@ -102,8 +117,16 @@ namespace ActsTrk
                                          const std::vector<small_vector<const xAOD::SpacePoint *>> &measToSp,
                                          const InDetDD::SiDetectorElementCollection *detectorElements,
                                          size_t offset) const;
+
+    // static member functions used by TrackStatePrinter.icc
+    static void printParameters(const Acts::Surface &surface, const Acts::GeometryContext &tgContext, const Acts::BoundVector &bound);
+    static std::string actsSurfaceName(const Acts::Surface &surface);
+    static std::string trackStateName(Acts::ConstTrackStateType trackStateType);
+
   };
 
 } // namespace
 
+#include "src/TrackStatePrinter.icc"
+
 #endif
diff --git a/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.icc b/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.icc
new file mode 100644
index 0000000000000000000000000000000000000000..fd10f19ebdbb867f6db6cb002dc865f07a5f4ab1
--- /dev/null
+++ b/Tracking/Acts/ActsTrackReconstruction/src/TrackStatePrinter.icc
@@ -0,0 +1,157 @@
+/*
+  Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
+*/
+
+#ifndef ACTSTRACKRECONSTRUCTION_TRACKSTATEPRINTER_ICC
+#define ACTSTRACKRECONSTRUCTION_TRACKSTATEPRINTER_ICC 1
+
+// ATHENA
+#include "xAODMeasurementBase/UncalibratedMeasurementContainer.h"
+#include "ActsGeometry/ATLASSourceLink.h"
+
+// ACTS CORE
+#include "Acts/Geometry/TrackingGeometry.hpp"
+#include "Acts/EventData/TrackParameters.hpp"
+
+// Other
+#include <iostream>
+#include <sstream>
+
+namespace ActsTrk
+{
+  /// format all arguments and return as a string.
+  /// Used here to apply std::setw() to the combination of values.
+  template <typename... Types>
+  static std::string to_string(Types &&...values)
+  {
+    std::ostringstream os;
+    (os << ... << values);
+    return os.str();
+  }
+
+  template <typename track_container_t>
+  void
+  TrackStatePrinter::printTrack(const Acts::GeometryContext &tgContext,
+                                const track_container_t &tracks,
+                                const typename track_container_t::TrackProxy &track,
+                                const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &container_offset) const
+  {
+    const auto lastMeasurementIndex = track.tipIndex();
+    // to print track states from inside outward, we need to reverse the order of visitBackwards().
+    using PrintTrackStateContainer = std::decay_t<decltype(tracks.trackStateContainer())>;
+    std::vector<typename PrintTrackStateContainer::ConstTrackStateProxy> states;
+    states.reserve(lastMeasurementIndex + 1); // could be an overestimate
+    size_t npixel = 0, nstrip = 0;
+    tracks.trackStateContainer().visitBackwards(
+        lastMeasurementIndex,
+        [&states, &npixel, &nstrip](const PrintTrackStateContainer::ConstTrackStateProxy &state) -> void
+        {
+          if (state.hasCalibrated())
+          {
+            if (state.calibratedSize() == 1)
+              ++nstrip;
+            else if (state.calibratedSize() == 2)
+              ++npixel;
+          }
+          states.push_back(state);
+        });
+
+    if (track.nMeasurements() + track.nOutliers() != npixel + nstrip)
+    {
+      ATH_MSG_WARNING("Track has " << track.nMeasurements() + track.nOutliers() << " measurements + outliers, but "
+                                    << npixel + nstrip << " pixel + strip hits");
+    }
+
+    const Acts::BoundTrackParameters per(track.referenceSurface().getSharedPtr(),
+                                          track.parameters(),
+                                          track.covariance(),
+                                          track.particleHypothesis());
+    std::cout << std::setw(5) << lastMeasurementIndex << ' '
+              << std::left
+              << std::setw(4) << "parm" << ' '
+              << std::setw(21) << actsSurfaceName(per.referenceSurface()) << ' '
+              << std::setw(22) << to_string("#hit=", npixel, '/', nstrip, ", #hole=", track.nHoles()) << ' '
+              << std::right;
+    printParameters(per.referenceSurface(), tgContext, per.parameters());
+    std::cout << std::fixed << std::setw(8) << ' '
+              << std::setw(7) << std::setprecision(1) << track.chi2() << ' '
+              << std::left
+              << "#out=" << track.nOutliers()
+              << ", #sh=" << track.nSharedHits()
+              << std::right << std::defaultfloat << std::setprecision(-1) << '\n';
+
+    for (auto i = states.size(); i > 0;)
+    {
+      printTrackState(tgContext, states[--i], container_offset);
+    }
+  }
+
+  template <typename track_state_proxy_t>
+  void
+  TrackStatePrinter::printTrackState(const Acts::GeometryContext &tgContext,
+                                     const track_state_proxy_t &state,
+                                     const std::vector<std::pair<const xAOD::UncalibratedMeasurementContainer *, size_t>> &container_offset,
+                                     bool useFiltered) const
+  {
+    if (!m_printFilteredStates && useFiltered)
+      return;
+
+    ptrdiff_t index = -1;
+
+    if (state.hasUncalibratedSourceLink())
+    {
+      ATLASUncalibSourceLink sl = state.getUncalibratedSourceLink().template get<ATLASUncalibSourceLink>();
+      index = (*sl)->index();
+      for (const auto &[container, offset] : container_offset)
+      {
+        if ((*sl)->container() == container)
+        {
+          index += offset;
+          break;
+        }
+      }
+    }
+
+    std::cout << std::setw(5) << state.index() << ' ';
+    char ptype = !m_printFilteredStates ? ' '
+                 : useFiltered          ? 'F'
+                                        : 'S';
+    if (state.hasCalibrated())
+    {
+      std::cout << ptype << std::setw(2) << state.calibratedSize() << 'D';
+    }
+    else if (state.typeFlags().test(Acts::TrackStateFlag::HoleFlag))
+    {
+      std::cout << std::setw(4) << "hole";
+    }
+    else
+    {
+      std::cout << ptype << std::setw(3) << " ";
+    }
+    std::cout << ' '
+              << std::left
+              << std::setw(21) << actsSurfaceName(state.referenceSurface()) << ' ';
+    if (index >= 0)
+    {
+      std::cout << std::setw(22) << index << ' ';
+    }
+    else
+    {
+      std::cout << std::setw(22) << to_string(state.referenceSurface().geometryId()) << ' ';
+    }
+    std::cout << std::right;
+    const auto &parameters = !useFiltered          ? state.parameters()
+                             : state.hasFiltered() ? state.filtered()
+                                                   : state.predicted();
+    printParameters(state.referenceSurface(), tgContext, parameters);
+    std::cout << ' '
+              << std::fixed
+              << std::setw(6) << std::setprecision(1) << state.pathLength() << ' '
+              << std::setw(7) << std::setprecision(1) << state.chi2() << ' '
+              << std::defaultfloat << std::setprecision(-1)
+              << std::setw(Acts::TrackStateFlag::NumTrackStateFlags) << trackStateName(state.typeFlags()) << '\n';
+  }
+
+}  // namespace ActsTrk
+
+#endif