Using RTTI with template metaprogramming involves a mix of compile-time and runtime type information techniques. While these two approaches can complement each other, there are some important implications to consider:
Template metaprogramming operates at compile-time, while RTTI provides information at runtime:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template<typename T>
void processType() {
// Compile-time check
if constexpr (std::is_integral_v<T>) {
std::cout << "Integral type\n";
} else {
std::cout << "Non-integral type\n";
}
// Runtime check
if (typeid(T) == typeid(int)) {
std::cout << "Type is int\n";
} else {
std::cout << "Type is not int\n";
}
}
int main() {
processType<int>();
processType<double>();
}
Integral type
Type is int
Non-integral type
Type is not int
Template metaprogramming typically has no runtime cost, while RTTI operations do. Mixing both can lead to performance trade-offs:
#include <chrono>
#include <iostream>
#include <typeinfo>
template <typename T>
void performanceTest(const T& value) {
using namespace std::chrono;
auto start = high_resolution_clock::now();
// Compile-time check (no runtime cost)
if constexpr (std::is_floating_point_v<T>) {
// Do something with floating point types
}
auto mid = high_resolution_clock::now();
// Runtime check (has runtime cost)
if (typeid(value) == typeid(double)) {
// Do something with double
}
auto end = high_resolution_clock::now();
std::cout
<< "Compile-time check: "
<< duration_cast<std::chrono::nanoseconds>(
mid - start).count() << " ns\n";
std::cout
<< "Runtime check: "
<< duration_cast<std::chrono::nanoseconds>(
end - mid).count() << " ns\n";
}
Template metaprogramming can be used to implement type erasure, which can then be combined with RTTI for runtime type checks:
#include <iostream>
#include <memory>
#include <typeinfo>
class Concept {
public:
virtual ~Concept() = default;
virtual const std::type_info& type() const = 0;
};
template <typename T>
class Model : public Concept {
public:
Model(const T& value) : value_(value) {}
const std::type_info& type() const override {
return typeid(T);
}
private:
T value_;
};
class Any {
public:
template <typename T>
Any(const T& value) : concept_(
std::make_unique<Model<T>>(value)) {}
const std::type_info& type() const {
return concept_->type();
}
private:
std::unique_ptr<Concept> concept_;
};
int main() {
Any a = 42;
Any b = 3.14;
std::cout << "a is of type: "
<< a.type().name() << '\n';
std::cout << "b is of type: "
<< b.type().name() << '\n';
}
a is of type: int
b is of type: double
SFINAE (Substitution Failure Is Not An Error) is a template metaprogramming technique that can be combined with RTTI for more flexible type-based function overloading:
#include <iostream>
#include <type_traits>
#include <typeinfo>
template<typename T>
typename std::enable_if<
std::is_integral<T>::value, void>::type
process(T value) {
std::cout << "Processing integral type: "
<< typeid(T).name() << '\n';
}
template<typename T>
typename std::enable_if<
!std::is_integral<T>::value, void>::type
process(T value) {
std::cout << "Processing non-integral type: "
<< typeid(T).name() << '\n';
}
int main() {
process(42);
process(3.14);
}
Processing integral type: int
Processing non-integral type: double
When using RTTI with template metaprogramming, it's important to be aware of these implications:
By understanding these implications, you can make informed decisions about when and how to combine RTTI with template metaprogramming techniques in your C++ code.
Answers to questions are automatically generated and may not have been reviewed.
typeid()
Learn to identify and react to object types at runtime using RTTI, dynamic casting and the typeid()
operator