diff --git a/src/language/CFunctionEmbedder.hpp b/src/language/CFunctionEmbedder.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..5aa9fdf26a58b3dbda3bdc61b47c2826d297c0d5
--- /dev/null
+++ b/src/language/CFunctionEmbedder.hpp
@@ -0,0 +1,80 @@
+#ifndef CFUNCTION_EMBEDDER_HPP
+#define CFUNCTION_EMBEDDER_HPP
+
+#include <PugsMacros.hpp>
+
+#include <cmath>
+#include <functional>
+#include <iostream>
+#include <tuple>
+#include <vector>
+
+struct ICFunctionEmbedder
+{
+  virtual void apply(const std::vector<ASTNodeDataVariant>& x, double& f_x) = 0;
+};
+
+template <typename FX, typename... Args>
+class CFunctionEmbedder : public ICFunctionEmbedder
+{
+ private:
+  std::function<FX(Args...)> m_f;
+  using ArgsTuple = std::tuple<Args...>;
+
+  template <size_t I>
+  PUGS_INLINE void
+  _copy_value(ArgsTuple& t, const std::vector<ASTNodeDataVariant>& v) const
+  {
+    std::visit(
+      [&](auto v_i) {
+        if constexpr (std::is_arithmetic_v<decltype(v_i)>) {
+          std::get<I>(t) = v_i;
+        } else {
+          std::cerr << __FILE__ << ':' << __LINE__ << ": unexpected argument type!\n";
+          std::exit(1);
+        }
+      },
+      v[I]);
+  }
+
+  template <size_t... I>
+  PUGS_INLINE void
+  _copy_from_vector(ArgsTuple& t, const std::vector<ASTNodeDataVariant>& v, std::index_sequence<I...>) const
+  {
+    (_copy_value<I>(t, v), ...);
+  }
+
+ public:
+  PUGS_INLINE
+  size_t
+  numberOfArguments() const
+  {
+    return sizeof...(Args);
+  }
+
+  PUGS_INLINE
+  void
+  apply(const std::vector<ASTNodeDataVariant>& x, FX& f_x) final
+  {
+    constexpr size_t N = std::tuple_size_v<ArgsTuple>;
+    ArgsTuple t;
+    using IndexSequence = std::make_index_sequence<N>;
+
+    this->_copy_from_vector(t, x, IndexSequence{});
+    f_x = std::apply(m_f, t);
+  }
+
+  // @note This is written in a template fashion to ensure that function type
+  // is correct. If one uses simply CFunctionEmbedder(std::function<FX(Args...)>&&),
+  // types seem unchecked
+  template <typename FX2, typename... Args2>
+  CFunctionEmbedder(std::function<FX2(Args2...)> f) : m_f(f)
+  {
+    static_assert(std::is_same_v<FX, FX2>, "incorrect return type");
+    static_assert(sizeof...(Args) == sizeof...(Args2), "invalid number of arguments");
+    using Args2Tuple = std::tuple<Args2...>;
+    static_assert(std::is_same_v<ArgsTuple, Args2Tuple>, "invalid arguments type");
+  }
+};
+
+#endif   // CFUNCTION_EMBEDDER_HPP
diff --git a/src/language/node_processor/CFunctionProcessor.hpp b/src/language/node_processor/CFunctionProcessor.hpp
index 139e54f7c58cd91799c997dd6d4f659e564444b1..4bbda59f92461bdcefe1ebe111297c674e268216 100644
--- a/src/language/node_processor/CFunctionProcessor.hpp
+++ b/src/language/node_processor/CFunctionProcessor.hpp
@@ -5,13 +5,7 @@
 
 #include <node_processor/INodeProcessor.hpp>
 
-#include <cmath>
-
-#include <cmath>
-#include <functional>
-#include <iostream>
-#include <tuple>
-#include <vector>
+#include <CFunctionEmbedder.hpp>
 
 template <typename ProvidedValueType, typename ExpectedValueType>
 class CFunctionArgumentProcessor final : public INodeProcessor
@@ -38,73 +32,6 @@ class CFunctionArgumentProcessor final : public INodeProcessor
   {}
 };
 
-struct IFunctionEmbedder
-{
-  virtual void apply(const std::vector<ASTNodeDataVariant>& x, double& f_x) = 0;
-};
-
-template <typename FX, typename... Args>
-class FunctionEmbedder : public IFunctionEmbedder
-{
- private:
-  std::function<FX(Args...)> m_f;
-  using ArgsTuple = std::tuple<Args...>;
-
-  template <size_t I>
-  void
-  _copy_value(ArgsTuple& t, const std::vector<ASTNodeDataVariant>& v) const
-  {
-    std::visit(
-      [&](auto v_i) {
-        if constexpr (std::is_arithmetic_v<decltype(v_i)>) {
-          std::get<I>(t) = v_i;
-        } else {
-          std::cerr << __FILE__ << ':' << __LINE__ << ": unexpected argument type!\n";
-          std::exit(1);
-        }
-      },
-      v[I]);
-  }
-
-  template <size_t... I>
-  void
-  _copy_from_vector(ArgsTuple& t, const std::vector<ASTNodeDataVariant>& v, std::index_sequence<I...>) const
-  {
-    (_copy_value<I>(t, v), ...);
-  }
-
- public:
-  // @warning This is written in a template fashion to ensure that function type
-  // is correct. If one uses simply FunctionEmbedder(std::function<FX(Args...)>&&),
-  // types seem unchecked
-  template <typename FX2, typename... Args2>
-  FunctionEmbedder(std::function<FX2(Args2...)> f) : m_f(f)
-  {
-    static_assert(std::is_same_v<FX, FX2>, "incorrect return type");
-    static_assert(sizeof...(Args) == sizeof...(Args2), "invalid number of arguments");
-    using Args2Tuple = std::tuple<Args2...>;
-    static_assert(std::is_same_v<ArgsTuple, Args2Tuple>, "invalid arguments type");
-  }
-
-  PUGS_INLINE
-  size_t
-  numberOfArguments() const
-  {
-    return sizeof...(Args);
-  }
-
-  void
-  apply(const std::vector<ASTNodeDataVariant>& x, FX& f_x) final
-  {
-    constexpr size_t N = std::tuple_size_v<ArgsTuple>;
-    ArgsTuple t;
-    using IndexSequence = std::make_index_sequence<N>;
-
-    this->_copy_from_vector(t, x, IndexSequence{});
-    f_x = std::apply(m_f, t);
-  }
-};
-
 template <typename ReturnType, typename ExpressionValueType>
 class CFunctionExpressionProcessor final : public INodeProcessor
 {
@@ -113,7 +40,7 @@ class CFunctionExpressionProcessor final : public INodeProcessor
 
   std::vector<ASTNodeDataVariant>& m_argument_values;
 
-  std::unique_ptr<IFunctionEmbedder> m_embedded_function;
+  std::unique_ptr<ICFunctionEmbedder> m_embedded_function;
 
  public:
   void
@@ -131,7 +58,7 @@ class CFunctionExpressionProcessor final : public INodeProcessor
   CFunctionExpressionProcessor(ASTNode& node, std::vector<ASTNodeDataVariant>& argument_values)
     : m_node{node}, m_argument_values{argument_values}
   {
-    m_embedded_function = std::make_unique<FunctionEmbedder<double, double, double>>(
+    m_embedded_function = std::make_unique<CFunctionEmbedder<double, double, double>>(
       std::function{[](double x, double y) -> double { return std::sin(x) * std::cos(3 * x) + y; }});
   }
 };