C++

C++ - [Templates 3] Template Deduction, Instantiation

Template Argument Deduction

Posted by Rico's Nerd Cluster on February 12, 2023

Template Argument Deduction

Direct template argument substitution works! So template argument reduction could work in this case.

1
2
3
4
5
6
template <class LidarMsg>
void process_pt_cloud(const std::shared_ptr<LidarMsg>& msg);
sensor_msgs::msg::PointCloud2::SharedPtr pc2_msg;   // std::shared_ptr<sensor_msgs::msg::PointCloud2>
process_pt_cloud(pc2_msg);

// Fine, LidarMsg = sensor_msgs::msg::PointCloud2 ✅

A qualified-id is not deducible in templates, because the compiler needs to “reverse-engineer” to check LidarMsg

1
2
3
4
5
6
7
template <class LidarMsg>
void process_pt_cloud(const typename LidarMsg::SharedPtr& msg);

using SharedPtr = std::shared_ptr<PointCloud2>;

sensor_msgs::msg::PointCloud2::SharedPtr pc2_msg;
process_pt_cloud(pc2_msg);

In this case, ?::SharedPtr = sensor_msgs::msg::PointCloud2::SharedPtr. The compiler is NOT smart enough to look that up reversely.

Template Instantiation

Template Instantiation

Free (non-member) Template Functions

1
2
template <typename T>
void foo(T x) { ... }

When you call foo(42), the compiler needs to instantiate foo<int> and this requires the definition of foo<T> to be visible at the point of calling. If you define the function in a .cpp file, the definition there is not an instantiation for other TUs to see. Therefore, template functions must be instantiated in header files

Template Classes

Member functions in a template class suffer the same issue. Then need to be instantiated in a header file so other functions can see them. One mitigation is to instantiate them at the bottom of a .cpp file, but that’s non-standard.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// .hpp
template <typename T>
class Bar {
public:
    void baz();
};

// .cpp
#include "bar.hpp"

template <typename T>
void Bar<T>::baz() {
    // body
}
template class Bar<int>;

Therefore, it’s nice to define these functions in the same .hpp file.