Negative Values in User-Defined Literals

How do we handle negative values in user-defined literals?

Handling negative values in user-defined literals requires understanding the precedence rules in C++.

The key point is that the negation operator (-) has lower precedence than user-defined literals. This means the literal function is called with a positive value first, and then the result is negated.

Example with Custom Types

Here's an example demonstrating this behavior with a custom Distance type:

#include <iostream>

class Distance {
public:
  Distance(float value) : value{value} {}

  Distance operator-() const {
    return Distance{-value};
  }

  float value;
};

std::ostream& operator<<(
  std::ostream& os, Distance d) {
  os << d.value << " meters\n";
  return os;
}

Distance operator""_meters(long double val) {
  return Distance{static_cast<float>(val)};
}

int main() {
  Distance d1 = -5.0_meters; 
  std::cout << d1;
}
-5 meters

Precedence Rules

The above code works because:

  1. 5.0_meters calls operator""_meters with 5.0 as an argument.
  2. The result is a Distance object with a value of 5.0.
  3. The negation operator (-) is then applied to this Distance object, invoking the overloaded operator- function.

Handling Negative Values Directly

If you need to handle negative values within the literal itself, consider implementing appropriate logic within the literal function. However, this is uncommon and usually unnecessary due to the precedence rules.

Example with Integers

Here's an example with integer literals:

#include <iostream>

int operator""_km(unsigned long long val) {
  return static_cast<int>(val * 1000);
}

int main() {
  int distance = -3_km; 
  std::cout << distance << " meters\n";
}
-3000 meters

Common Pitfalls

  • Order of Operations: Remember that the literal function is called first, and then the result is negated.
  • Operator Overloading: Ensure that the type returned by your literal supports the unary operator if you need to handle negation.

Conclusion

Handling negative values in user-defined literals relies on understanding operator precedence.

The literal function processes the positive value first, and then the result can be negated. By correctly implementing and overloading the necessary operators, you can effectively manage negative values in your custom literals.

User Defined Literals

A practical guide to user-defined literals in C++, which allow us to write more descriptive and expressive values

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Custom Types and User-Defined Literals
Can user-defined literals be used with custom types?
Portability of User-Defined Literals
How can we ensure that our user-defined literals are portable across different compilers?
Underscore in User-Defined Literals
Why must user-defined literals start with an underscore?
Namespaces for User-Defined Literals
How do user-defined literals interact with namespaces?
Best Practices for User-Defined Literals
What are the best practices for using user-defined literals in large projects?
Overloading User-Defined Literals
Can user-defined literals be overloaded?
User-Defined Literals and Template Classes
How do user-defined literals work with template classes?
Or Ask your Own Question
Get an immediate answer to your specific question using our AI assistant