When and how to use a template literal operator?

There is a mention in cppreference that you can use template user literals with some restrictions:

If the literal operator is a template, it must have an empty list of parameters and may have only one template parameter, which should be a non-parametric package of template parameters with the char element type, for example

 template <char...> double operator "" _x(); 

So, I wrote one, as in the code below:

 template <char...> double operator "" _x() { return .42; } int main() { 10_x; // empty template list, how to specify non-empty template parameters? } 

Question:

  • The code works, but how can I use a statement with some non-empty template parameters? 10_x<'a'>; or 10_<'a'>x; not compiled.
  • Do you have an example of using such template operators in the world?
+7
c ++ c ++ 11 templates c ++ 14 user-defined-literals
source share
3 answers
 10_x; // empty template list, how to specify non-empty template parameters? 

This is not entirely correct. The list of template options is not empty. When you write:

 template <char... Cs> ??? operator "" _x() 

Cs filled from the material on the left side of the literal. That is, when you write:

 10_x 

which causes:

 operator ""_x<'1', '0'>(); 

One simple example is to build compilation time overflowing a binary literal so that:

 template <uint64_t V> constexpr uint64_t make_binary() { return V; } template <uint64_t V, char C, char... Cs> constexpr uint64_t make_binary() { static_assert(C == '0' || C == '1', "invalid binary"); return make_binary<2*V + C - '0', Cs...>(); } template <char... Cs> uint64_t operator "" _b() { static_assert(sizeof...(Cs) <= 64, "overflow"); return make_binary<0, Cs...>(); } uint64_t a = 101_b; // OK: a == 5 uint64_t b = 102_b; // error: invalid uint64_t c = 11111111110000000000111111111100000000001111111111000000000011111111110000000000_b; // error: overflow 
+7
source share

The parameters of your template are already specified - they are source code symbols containing your literal value! So for 10_x you actually call:

 template<> double operator "" _x<'1', '0'>(); 

Here is a working example. It compiles without errors, and none of the statements start.

 #include <cassert> enum class MyEnum { ONE, TWO, THREE }; template<char...> MyEnum operator "" _e(); template<> MyEnum operator "" _e<'1'>() { return MyEnum::ONE; } template<> MyEnum operator "" _e<'2'>() { return MyEnum::TWO; } template<> MyEnum operator "" _e<'3'>() { return MyEnum::THREE; } int main() { assert(1_e == MyEnum::ONE); assert(2_e == MyEnum::TWO); assert(3_e == MyEnum::THREE); } 
+3
source share

You can somehow develop a package of parameters (as others have mentioned) or access them as a compile-time string if you prefer:

 template<int N> constexpr double f(const char(&str)[N]) { return .42; } template <char... C> constexpr double operator "" _x() { return f({C...}); } 

Do you have an example of the real use of such template operators?

You can use the above technique to deal with string and number conversion with compilation and have something like 10_x instead of f("10") or something else.

+2
source share

All Articles