From e5f8a6bbe33409cb27aeca674ebcdd0fe50d827e Mon Sep 17 00:00:00 2001 From: Patrik Huber Date: Mon, 27 Mar 2023 19:53:50 +0100 Subject: [PATCH] Add template keyword to fix dependent name errors Clang and GCC complained about this, and it's indeed needed (see e.g. https://eigen.tuxfamily.org/dox/TopicTemplateKeyword.html). MSVC accepts it without template keyword, but it's non-standard C++. Basically, the object that we call the templated function on (head<>() or cast<>()) is itself a templated type. Because we don't know at compile time what that first templated type is, the compiler can't know what the function is that we call on it (i.e. it could be a type or operator<()). So we need the "template" keyword to tell the compiler that it's a templated function. One way to avoid this would be to declare a template at namespace scope, like std::tuple: It has an associated get function template that is declared in the std namespace instead of being a class member, so we can do std::get(t) instead of t.template get(). However, that's not really a good solution here I think. There's also nothing wrong with using `template` here, it just makes the code a bit more difficult to read. --- include/eos/fitting/ceres_nonlinear.hpp | 26 +++++++++++++++--------- include/eos/render/matrix_projection.hpp | 6 +++++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/eos/fitting/ceres_nonlinear.hpp b/include/eos/fitting/ceres_nonlinear.hpp index 131c3fa9..31811e85 100644 --- a/include/eos/fitting/ceres_nonlinear.hpp +++ b/include/eos/fitting/ceres_nonlinear.hpp @@ -168,8 +168,8 @@ struct PerspectiveProjectionLandmarkCost Eigen::Map> translation(camera_translation); Eigen::Matrix4 model_view_mtx = Eigen::Matrix4::Identity(); - model_view_mtx.block<3, 3>(0, 0) = rotation.toRotationMatrix(); - model_view_mtx.col(3).head<3>() = translation; + model_view_mtx.template block<3, 3>(0, 0) = rotation.toRotationMatrix(); // dependent name + model_view_mtx.col(3).template head<3>() = translation; // dependent name // Todo: use get_opencv_viewport() from nonlin_cam_esti.hpp. const Eigen::Vector4 viewport(T(0), T(image_height), T(image_width), @@ -296,8 +296,8 @@ struct VertexColorCost Eigen::Map> translation(camera_translation); Eigen::Matrix4 model_view_mtx = Eigen::Matrix4::Identity(); - model_view_mtx.block<3, 3>(0, 0) = rotation.toRotationMatrix(); - model_view_mtx.col(3).head<3>() = translation; + model_view_mtx.template block<3, 3>(0, 0) = rotation.toRotationMatrix(); // dependent name + model_view_mtx.col(3).template head<3>() = translation; // dependent name // Todo: use get_opencv_viewport() from nonlin_cam_esti.hpp. const Eigen::Vector4 viewport(T(0), T(image.height()), T(image.width()), @@ -385,9 +385,12 @@ Eigen::Vector3 get_shape_at_point(const eos::morphablemodel::PcaModel& shape_ { // Computing Shape = mean + shape_basis*shape_coeffs + blendshapes*blendshape_coeffs: const Eigen::Vector3f mean = shape_model.get_mean_at_point(vertex_id); - const Eigen::Vector3 shape_vector = - shape_model.get_rescaled_pca_basis_at_point(vertex_id).leftCols(shape_coeffs.size()).cast() * - shape_coeffs; + // Note: We seem to have a dependent name here, so we need 'template', to help the compiler that 'cast' + // is a template. + const Eigen::Vector3 shape_vector = shape_model.get_rescaled_pca_basis_at_point(vertex_id) + .leftCols(shape_coeffs.size()) + .template cast() * + shape_coeffs; Eigen::Vector3 expression_vector(T(0.0), T(0.0), T(0.0)); for (std::size_t i = 0; i < blendshape_coeffs.size(); i++) { @@ -412,9 +415,12 @@ Eigen::Vector3 get_vertex_color_at_point(const eos::morphablemodel::PcaModel& Eigen::Map> color_coeffs) { const Eigen::Vector3f mean = color_model.get_mean_at_point(vertex_id); - const Eigen::Vector3 color_vector = - color_model.get_rescaled_pca_basis_at_point(vertex_id).leftCols(color_coeffs.size()).cast() * - color_coeffs; + // Note: We seem to have a dependent name here, so we need 'template', to help the compiler that 'cast' + // is a template. + const Eigen::Vector3 color_vector = color_model.get_rescaled_pca_basis_at_point(vertex_id) + .leftCols(color_coeffs.size()) + .template cast() * + color_coeffs; return Eigen::Vector3(mean.cast() + color_vector); }; diff --git a/include/eos/render/matrix_projection.hpp b/include/eos/render/matrix_projection.hpp index 5a037bc5..b9cfe533 100644 --- a/include/eos/render/matrix_projection.hpp +++ b/include/eos/render/matrix_projection.hpp @@ -156,7 +156,11 @@ Eigen::Vector3 project(const Eigen::Vector3& point_3d, const Eigen::Matrix projected_point.x() = projected_point.x() * T(viewport(2)) + T(viewport(0)); projected_point.y() = projected_point.y() * T(viewport(3)) + T(viewport(1)); - return projected_point.head<3>(); + // Note: We need the 'template' keyword, as we have a dependent name - 'T' is unknown when the compiler + // parses this expression, so we need to tell it that 'head<3>()' is a template function (and not e.g. an + // 'operator<' or something like that). We could alternatively rewrite this as: + // 'return Eigen::Vector3(projected_point.x(), projected_point.y(), projected_point.z());' + return projected_point.template head<3>(); }; } /* namespace render */