User-defined literals can be used with template classes to create flexible and reusable code. Here’s how you can integrate user-defined literals with template classes:
First, let's define a template class Quantity
that can represent different types of measurements (e.g., distance, weight, etc.):
#include <iostream>
template <typename Unit>
class Quantity {
public:
explicit Quantity(float value)
: value{value} {}
float value;
};
template <typename Unit>
std::ostream& operator<<(
std::ostream& os, const Quantity<Unit>& q) {
os << q.value << " " << Unit::name();
return os;
}
Next, we’ll define user-defined literals for specific units. Each unit will be a class with a static method name()
to provide the unit’s name:
#include <iostream>
class Quantity {/*...*/};
struct Meters {
static std::string name() { return "meters"; }
};
struct Kilometers {
static std::string name() { return "kilometers"; }
};
Quantity<Meters> operator""_m(long double val) {
return Quantity<Meters>{static_cast<float>(val)};
}
Quantity<Kilometers> operator""_km(long double val) {
return Quantity<Kilometers>{static_cast<float>(val)};
}
int main() {
auto distance1 = 5.0_m;
auto distance2 = 3.5_km;
std::cout << distance1 << "\n";
std::cout << distance2 << "\n";
}
5 meters
3.5 kilometers
You can combine user-defined literals with other templates, such as conversion functions. The following example has a convertTo()
template function within the Quantity
template class.
We then use template specialization to provide an implementation of that function for converting kilometers to meters:
#include <iostream>
#include <string>
template <typename Unit>
class Quantity {
public:
explicit Quantity(float value)
: value{value} {}
float value;
float getValue() const { return value; }
template <typename U>
Quantity<U> convertTo() const;
};
template <typename Unit>
std::ostream& operator<<(
std::ostream& os, const Quantity<Unit>& q) {
os << q.value << " " << Unit::name();
return os;
}
struct M {
static std::string name() {
return "meters";
}
};
struct KM {
static std::string name() {
return "kilometers";
}
};
template <>
template <>
Quantity<M> Quantity<KM>::convertTo<M>() const {
return Quantity<M>{value * 1000};
}
Quantity<M> operator""_m(long double val) {
return Quantity<M>{static_cast<float>(val)};
}
Quantity<KM> operator""_km(long double val) {
return Quantity<KM>{static_cast<float>(val)};
}
int main() {
auto distance1 = 5.0_m;
auto distance2 = 1.5_km;
auto distance_m = distance2.convertTo<M>();
std::cout << distance1 << "\n";
std::cout << distance2 << "\n";
std::cout << distance_m << "\n";
}
5 meters
1.5 kilometers
1500 meters
Using user-defined literals with template classes enhances the expressiveness and reusability of your code.
Template classes provide a type-safe way to manage different units and operations, while user-defined literals offer a convenient syntax for creating these objects. This combination is powerful for writing clear, maintainable, and flexible C++Â code.
Answers to questions are automatically generated and may not have been reviewed.
A practical guide to user-defined literals in C++, which allow us to write more descriptive and expressive values