RawAndCookedEng

Raw and Cooked

C++11 has user-defined literals for characters, C strings, integers, and floating-point numbers. Integers and floating-point numbers are available in raw and cooked form. Thanks to C++14, we have built-in literals for binary numbers, C++ strings, complex numbers, and time units.

 

The four user-defined literals

After the example in the last post user-defined literals I will provide – as promised – the details in this post. To make my intention clear, here are the literal types, including the raw and cooked variations:

RawAndCookedEng

How should you read the table? The data type character has the form character_suffix. An example is ‘s’_c. The compiler invokes the literal operator operator”” _c(‘s’). The character is, in this case, a char. C++ supports, in addition to the data type char the data types wchar_t, char16_t, and char32_t. You can use this type as a base for your C string. I used in the table a char. The table shows that the compiler maps the C string “hi”_i18 to the literal operator operator”” _i18n(“hi”,2). 2 is the length of the c string.

The compiler can map integers or floating-point numbers to integers (unsigned long long int) or floating-point numbers (long double), but the compiler can also map them to C strings. The first variant is called the cooked form; the second variant is the raw form. The compiler will use the raw form if the literal operator wants its arguments as a C string. If not, it uses the cooked form. If you implement both versions, the compiler will choose the cooked form.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

    Admittedly, in the last lines is a lot of confusion potential. Therefore, I sum it all up from the perspective of the signatures in the following table. The first column has the signature of the literal operator, the second column is the type of the user-defined literal, and the last column an example for a user-defined literal that fits the signature of the literal operator.

    literaleSignaturEng

    Calculate it once more

    I calculated in the post user-defined literals how many meters I have to go by car on average per week. I made my calculation based on user-defined literals of the type long double in the cooked form. I have to adjust the literal operators to make my calculation in the raw form.

    It’s only necessary to convert the arguments of the literal operator from type C string to long double. That is relatively easy to do with the new function std::stold.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    // unit.h
    
    #ifndef UNIT_H
    #define UNIT_H
    
    #include <distance.h>
    
    namespace Distance{
    
      namespace Unit{
        MyDistance operator "" _km(const char* k){
          return MyDistance(1000* std::stold(k));
        }
        MyDistance operator "" _m(const char* m){
          return MyDistance(std::stold(m));
        }
        MyDistance operator "" _dm(const char* d){
          return MyDistance(std::stold(d)/10);
        }
        MyDistance operator "" _cm(const char* c){
          return MyDistance(std::stold(c)/100);
        }
      }
    }
    
    #endif
    

     

    Either I have not touched the class MyDistance.

     

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    // distance.h
    
    #ifndef DISTANCE_H
    #define DISTANCE_H
    
    #include <iostream>
    #include <ostream>
    
    
    namespace Distance{
      class MyDistance{
        public:
          MyDistance(double i):m(i){}
    
          friend MyDistance operator+(const MyDistance& a, const MyDistance& b){
            return MyDistance(a.m + b.m);
          }
          friend MyDistance operator-(const MyDistance& a,const MyDistance& b){
            return MyDistance(a.m - b.m);
          }
    	  
    	  friend MyDistance operator*(double m, const MyDistance& a){
    	    return MyDistance(m*a.m);
    	  }
    	  
    	  friend MyDistance operator/(const MyDistance& a, int n){
    	    return MyDistance(a.m/n);
    	  }
    	  
          friend std::ostream& operator<< (std::ostream &out, const MyDistance& myDist){
            out << myDist.m << " m";
            return out;
          }
    	private:
    	  double m;
    	  
      };
      
    }
      
    Distance::MyDistance getAverageDistance(std::initializer_list<Distance::MyDistance> inList){
      auto sum= Distance::MyDistance{0.0};
      for (auto i: inList) sum = sum + i ;
      return sum/inList.size(); 
    }
    
    
    #endif
    

     

    Nor does the main program need a modification.

     

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    // average.cpp
    
    #include <distance.h>
    #include <unit.h>
    
    using namespace Distance::Unit;
    
    int main(){
    
      std:: cout << std::endl;
    
      std::cout << "1.0_km: " << 1.0_km << std::endl;
      std::cout << "1.0_m: " << 1.0_m << std::endl;
      std::cout << "1.0_dm: " << 1.0_dm << std::endl;
      std::cout << "1.0_cm: " << 1.0_cm << std::endl;
      
      std::cout << std::endl;
    
      std::cout << "0.001 * 1.0_km: " << 0.001 * 1.0_km << std::endl;
      std::cout << "10 * 1_dm: " << 10 * 1.0_dm << std::endl;
      std::cout << "100 * 1.0cm: " << 100 * 1.0_cm << std::endl;
      std::cout << "1_.0km / 1000: " << 1.0_km / 1000 << std::endl;
    
      std::cout << std::endl;
      std::cout << "1.0_km + 2.0_dm +  3.0_dm + 4.0_cm: " << 1.0_km + 2.0_dm +  3.0_dm + 4.0_cm << std::endl;
      std::cout << std::endl;
      
      auto work= 63.0_km;
      auto workPerDay= 2 * work;
      auto abbrevationToWork= 5400.0_m;
      auto workout= 2 * 1600.0_m;
      auto shopping= 2 * 1200.0_m;
      
      auto distPerWeek1= 4*workPerDay-3*abbrevationToWork+ workout+ shopping;
      auto distPerWeek2= 4*workPerDay-3*abbrevationToWork+ 2*workout;
      auto distPerWeek3= 4*workout + 2*shopping;
      auto distPerWeek4= 5*workout + shopping;
    
      std::cout << "distPerWeek1: " << distPerWeek1 << std::endl;
      
      auto averageDistance= getAverageDistance({distPerWeek1,distPerWeek2,distPerWeek3,distPerWeek4});
      std::cout<< "averageDistance: " << averageDistance << std::endl;
      
      std::cout << std::endl;
    
    }
    

     

    Of course, the result is the same.

     average

     

    New built-in literals with C++14

    C++ added with C++14 a few new built-in literals. These are built-in literals for binary numbers, C++ strings, complex numbers, and time units. First, here is the overview.

    CppLiteralsEng

    You have to keep a few special rules in mind. The binary numbers start with the prefix 0b. The built-in literals have no underscore. That is different from the user-defined literals. C++ support with C++14 the first time a C++ string literal. So far, C++ supports only C-string literals. That means, for example, that you always have to use a C string literal to initialize a C++ string. That was very strange. The time literals are very convenient because they implicitly know their unit. They are of the type std::chrono::duration.

    The base unit for time is the second. My 16-year-old son often complains that his school day is exhausting. Of course, the question arises. How many seconds does my son need for a typical school day? The program answers.

     

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    // literals.cpp
    
    #include <iostream>
    #include <chrono>
    
    using namespace std::literals::chrono_literals;
    
    int main(){
    
      std::cout << std::endl;
    
      auto schoolHour= 45min;
    
      auto shortBreak= 300s;
      auto longBreak= 0.25h;
    
      auto schoolWay= 15min;
      auto homework= 2h;
    
      auto schoolDayInSeconds= 2*schoolWay + 6 * schoolHour + 4 * shortBreak + longBreak + homework;
      
      std::cout << "School day in seconds: " << schoolDayInSeconds.count() << std::endl;
      
      std::cout << "School day in minutes: " << schoolDayInSeconds.count() / 60 << std::endl;
      
      std::cout << "School day in hours: " << schoolDayInSeconds.count() / 3600 << std::endl;
    
      std::cout << std::endl;
    
    

     

    I think the program is self-explanatory. The suffixes are expressive enough. Making the correct additions is the job of the compiler. The time literals support the base arithmetic addition, subtraction, multiplication, division, and modulo operation.

    I have no C++14-compliant compiler at my disposal. Not really an issue. The online compiler on en.cppreference.com gives me the answers

    My son needs 27300 seconds for all his task related to school. This is almost a typical working day in Germany of about 8 hours.

     schoolDay

    What’s next?

    The classical enumerations (enum) in C++ have three big disadvantages.

    1. They convert implicitly to int.
    2. They introduce their enumerators into the enclosing scope.
    3. The type of enumerators can not be defined.

    In particular, characteristics 1 and 2 are often a reason for bad surprises. The new strong-typed enumerations clear off these issues. Read about it in the next post.

     

     

     

     

     

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, moon, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *