Units for types in C++

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
13
down vote

favorite
3












In the C++ Core Guidlines P.1 change_speed example, it shows a Speed type that is used as shown below:



change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second


I am particularly interested in the last two lines of this example. The first seems to suggest that if you provide no units with the argument to change_speed it will throw an error. The last line shows the units defined using some the m and s literals. Are both of these new features in modern versions of C++? If so, how would something like this be implemented, and what version of C++ is required?










share|improve this question

















  • 12




    cppreference
    – Tyker
    Aug 21 at 7:15










  • Perhaps this is what you ment: It won't throw an error, It won't compile, because change_speed takes a Speed and not a floating point literal.
    – hetepeperfan
    Aug 21 at 7:48














up vote
13
down vote

favorite
3












In the C++ Core Guidlines P.1 change_speed example, it shows a Speed type that is used as shown below:



change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second


I am particularly interested in the last two lines of this example. The first seems to suggest that if you provide no units with the argument to change_speed it will throw an error. The last line shows the units defined using some the m and s literals. Are both of these new features in modern versions of C++? If so, how would something like this be implemented, and what version of C++ is required?










share|improve this question

















  • 12




    cppreference
    – Tyker
    Aug 21 at 7:15










  • Perhaps this is what you ment: It won't throw an error, It won't compile, because change_speed takes a Speed and not a floating point literal.
    – hetepeperfan
    Aug 21 at 7:48












up vote
13
down vote

favorite
3









up vote
13
down vote

favorite
3






3





In the C++ Core Guidlines P.1 change_speed example, it shows a Speed type that is used as shown below:



change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second


I am particularly interested in the last two lines of this example. The first seems to suggest that if you provide no units with the argument to change_speed it will throw an error. The last line shows the units defined using some the m and s literals. Are both of these new features in modern versions of C++? If so, how would something like this be implemented, and what version of C++ is required?










share|improve this question













In the C++ Core Guidlines P.1 change_speed example, it shows a Speed type that is used as shown below:



change_speed(Speed s); // better: the meaning of s is specified
// ...
change_speed(2.3); // error: no unit
change_speed(23m / 10s); // meters per second


I am particularly interested in the last two lines of this example. The first seems to suggest that if you provide no units with the argument to change_speed it will throw an error. The last line shows the units defined using some the m and s literals. Are both of these new features in modern versions of C++? If so, how would something like this be implemented, and what version of C++ is required?







c++ cpp-core-guidelines






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Aug 21 at 7:14









rozzy

1,09731328




1,09731328







  • 12




    cppreference
    – Tyker
    Aug 21 at 7:15










  • Perhaps this is what you ment: It won't throw an error, It won't compile, because change_speed takes a Speed and not a floating point literal.
    – hetepeperfan
    Aug 21 at 7:48












  • 12




    cppreference
    – Tyker
    Aug 21 at 7:15










  • Perhaps this is what you ment: It won't throw an error, It won't compile, because change_speed takes a Speed and not a floating point literal.
    – hetepeperfan
    Aug 21 at 7:48







12




12




cppreference
– Tyker
Aug 21 at 7:15




cppreference
– Tyker
Aug 21 at 7:15












Perhaps this is what you ment: It won't throw an error, It won't compile, because change_speed takes a Speed and not a floating point literal.
– hetepeperfan
Aug 21 at 7:48




Perhaps this is what you ment: It won't throw an error, It won't compile, because change_speed takes a Speed and not a floating point literal.
– hetepeperfan
Aug 21 at 7:48












2 Answers
2






active

oldest

votes

















up vote
13
down vote



accepted










As mentioned in the comments, the example from the core guidelines uses user-defined literals to construct application-specific types that intuitively represent physical quantities. To illustrate them for the specific example, consider these types:



/* "Strong" speed type, unit is always [m/s]. */
struct Speed
long double value;
;

/* "Strong" length type, parameterized by a unit as multiples of [m]. */
template <class Period = std::ratio<1>> struct Length
unsigned long long value;
;


It probably doesn't make much sense to track the unit of Length objects, but not for Speed instances, but let's consider the simplest possible example here. Now, let's look at two user-defined literals:



#include <ratio>

auto operator ""_m(unsigned long long n)

return Length<>n;


auto operator ""_km(unsigned long long n)

return Length<std::kilo>n;



They let you instantiate Length objects like this:



/* We use auto here, because the suffix is so crystal clear: */
const auto lengthInMeter = 23_m;
const auto lengthInKilometer = 23_km;


In order to cosntruct a Speed instance, let's define an appropriate operator for dividing a Length by a duration:



#include <chrono>

template <class LengthRatio, class Rep, class DurationRatio>
auto operator / (const Length<LengthRatio>& lhs,
const std::chrono::duration<Rep, DurationRatio>& rhs)

const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);

return SpeedlengthFactor*lhs.value/rhsInSeconds.count();



Now, let's look at the example from the core guidelines again,



void change_speed(const Speed& s)

/* Complicated stuff... */



but most importantly, how you can call such a function:



using namespace std::chrono_literals;

int main(int, char **)

change_speed(23_m/1s);
change_speed(42_km/3600s);
change_speed(42_km/1h);

return 0;



As @KillzoneKid mentioned in the comments, C++11 is required for this to work.






share|improve this answer





























    up vote
    3
    down vote













    There are two different things involved in your code:



    1. The use of strong/unit types to make your code more robust, i.e., you differentiate two integer types. This is built-in in some languages (e.g., Ada), but not in C++, but you can create classes that wraps integer types to mimic such behavior (see below).


    2. The use of operator literals to create instances of such classes in user-friendly way, i.e., you write 1s instead of seconds1. This is simply a convenience feature, which can be useful in some places.


    Using strong integer types is very useful because it makes your code much less error prone*:



    • You cannot convert between types representing durations and lengths, as in real life.

    • Within types representing the same kind of things (e.g., seconds and hours), there are not implicit conversions if you lose precision, e.g., you cannot convert seconds to hours, unless you are representing our with floating point type (float / double).

    • The (implicit and non-implicit) conversions takes care of the scaling for you: you can convert hours to seconds without having to manually multiply by 3600.

    • You can provide realistic operators that will takes care of conversions for you, e.g., in your example, there is division operator between length and duration that gives speeds. The exact type of speed is automatically deduced from the type of the length and the type of duration:

    auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.


    • Unit types are self-documented: If a function returns microseconds, you know what this is, you do not have to hope that the guy documenting the function returning unsigned long long mentioned that this represents microseconds...

    * I am only talking about implicit conversion here, of course, you can do conversion explicitly, e.g., using duration_cast (loss of precision).




    Unit types



    Wrapping integer types in "unit" classes has always been available, but C++11 brought one standard wrapped integer type: std::chrono::duration.



    A "unit" class can be defined by:



    • the type of thing it represents: time, length, weight, speed, ...

    • the C++ type it uses to represent these data: int, double, ...

    • the ratio between this type and the "1-type" of the same unit.

    Currently, only duration-like types are provided by the standard, but there have been discussion (maybe a proposal?) for providing a more generic basic unit type such as:



    template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;


    ...where Unit would be a placeholder indicating the kind of thing represented, e.g.:



    struct length_t ;

    template <class Rep, class Ratio = std::ratio<1>>
    using length = unit<length_t, Rep, Ratio>;


    But this is not standard yet, so let's have a look at std::chrono::duration:



    template <class Rep, class Period = std::ratio<1>> class duration;


    The Rep template parameters is the C++ type:



    • Standard defined durations types have integer representations (implementation defined).

    • The underlying type defines the type of conversions that can be implicitly made:

      • You can convert integer hours to integer seconds implicitly (multiply by 3600).

      • You can convert integer seconds to integer hours implicitly because you would lose precision.

      • You can convert integer seconds to double hours.


    The Period template parameters defines the ratio between the duration type and one second (which is the basic duration chosen):




    • std::ratio is a very convenient standard-defined type that simply represent a ratio between two integers, with corresponding operations (*, /, ...).

    • The standad provides multiple duration types with various ratios: std::chrono::seconds, std::chrono::minutes, ...


    Operator literals



    These have been introduced in C++11 and are literals operators.



    The s one is standard and is included in the chrono standard library:



    using namespace std::chrono_literals;
    auto one_second = 1s;
    auto one_hour = 1h;


    The m one is not standard, and thus should be prefixed by _ (since it is user-defined), like 23_m. You can define your own operator like so:



    constexpr auto operator "" _m(unsigned long long ull) 
    return metersull;






    share|improve this answer




















    • Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
      – Oliv
      Aug 21 at 16:41










    • @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
      – Holt
      Aug 21 at 18:56










    • That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
      – Oliv
      Aug 22 at 8:24











    Your Answer





    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51943434%2funits-for-types-in-c%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    13
    down vote



    accepted










    As mentioned in the comments, the example from the core guidelines uses user-defined literals to construct application-specific types that intuitively represent physical quantities. To illustrate them for the specific example, consider these types:



    /* "Strong" speed type, unit is always [m/s]. */
    struct Speed
    long double value;
    ;

    /* "Strong" length type, parameterized by a unit as multiples of [m]. */
    template <class Period = std::ratio<1>> struct Length
    unsigned long long value;
    ;


    It probably doesn't make much sense to track the unit of Length objects, but not for Speed instances, but let's consider the simplest possible example here. Now, let's look at two user-defined literals:



    #include <ratio>

    auto operator ""_m(unsigned long long n)

    return Length<>n;


    auto operator ""_km(unsigned long long n)

    return Length<std::kilo>n;



    They let you instantiate Length objects like this:



    /* We use auto here, because the suffix is so crystal clear: */
    const auto lengthInMeter = 23_m;
    const auto lengthInKilometer = 23_km;


    In order to cosntruct a Speed instance, let's define an appropriate operator for dividing a Length by a duration:



    #include <chrono>

    template <class LengthRatio, class Rep, class DurationRatio>
    auto operator / (const Length<LengthRatio>& lhs,
    const std::chrono::duration<Rep, DurationRatio>& rhs)

    const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
    const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);

    return SpeedlengthFactor*lhs.value/rhsInSeconds.count();



    Now, let's look at the example from the core guidelines again,



    void change_speed(const Speed& s)

    /* Complicated stuff... */



    but most importantly, how you can call such a function:



    using namespace std::chrono_literals;

    int main(int, char **)

    change_speed(23_m/1s);
    change_speed(42_km/3600s);
    change_speed(42_km/1h);

    return 0;



    As @KillzoneKid mentioned in the comments, C++11 is required for this to work.






    share|improve this answer


























      up vote
      13
      down vote



      accepted










      As mentioned in the comments, the example from the core guidelines uses user-defined literals to construct application-specific types that intuitively represent physical quantities. To illustrate them for the specific example, consider these types:



      /* "Strong" speed type, unit is always [m/s]. */
      struct Speed
      long double value;
      ;

      /* "Strong" length type, parameterized by a unit as multiples of [m]. */
      template <class Period = std::ratio<1>> struct Length
      unsigned long long value;
      ;


      It probably doesn't make much sense to track the unit of Length objects, but not for Speed instances, but let's consider the simplest possible example here. Now, let's look at two user-defined literals:



      #include <ratio>

      auto operator ""_m(unsigned long long n)

      return Length<>n;


      auto operator ""_km(unsigned long long n)

      return Length<std::kilo>n;



      They let you instantiate Length objects like this:



      /* We use auto here, because the suffix is so crystal clear: */
      const auto lengthInMeter = 23_m;
      const auto lengthInKilometer = 23_km;


      In order to cosntruct a Speed instance, let's define an appropriate operator for dividing a Length by a duration:



      #include <chrono>

      template <class LengthRatio, class Rep, class DurationRatio>
      auto operator / (const Length<LengthRatio>& lhs,
      const std::chrono::duration<Rep, DurationRatio>& rhs)

      const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
      const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);

      return SpeedlengthFactor*lhs.value/rhsInSeconds.count();



      Now, let's look at the example from the core guidelines again,



      void change_speed(const Speed& s)

      /* Complicated stuff... */



      but most importantly, how you can call such a function:



      using namespace std::chrono_literals;

      int main(int, char **)

      change_speed(23_m/1s);
      change_speed(42_km/3600s);
      change_speed(42_km/1h);

      return 0;



      As @KillzoneKid mentioned in the comments, C++11 is required for this to work.






      share|improve this answer
























        up vote
        13
        down vote



        accepted







        up vote
        13
        down vote



        accepted






        As mentioned in the comments, the example from the core guidelines uses user-defined literals to construct application-specific types that intuitively represent physical quantities. To illustrate them for the specific example, consider these types:



        /* "Strong" speed type, unit is always [m/s]. */
        struct Speed
        long double value;
        ;

        /* "Strong" length type, parameterized by a unit as multiples of [m]. */
        template <class Period = std::ratio<1>> struct Length
        unsigned long long value;
        ;


        It probably doesn't make much sense to track the unit of Length objects, but not for Speed instances, but let's consider the simplest possible example here. Now, let's look at two user-defined literals:



        #include <ratio>

        auto operator ""_m(unsigned long long n)

        return Length<>n;


        auto operator ""_km(unsigned long long n)

        return Length<std::kilo>n;



        They let you instantiate Length objects like this:



        /* We use auto here, because the suffix is so crystal clear: */
        const auto lengthInMeter = 23_m;
        const auto lengthInKilometer = 23_km;


        In order to cosntruct a Speed instance, let's define an appropriate operator for dividing a Length by a duration:



        #include <chrono>

        template <class LengthRatio, class Rep, class DurationRatio>
        auto operator / (const Length<LengthRatio>& lhs,
        const std::chrono::duration<Rep, DurationRatio>& rhs)

        const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
        const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);

        return SpeedlengthFactor*lhs.value/rhsInSeconds.count();



        Now, let's look at the example from the core guidelines again,



        void change_speed(const Speed& s)

        /* Complicated stuff... */



        but most importantly, how you can call such a function:



        using namespace std::chrono_literals;

        int main(int, char **)

        change_speed(23_m/1s);
        change_speed(42_km/3600s);
        change_speed(42_km/1h);

        return 0;



        As @KillzoneKid mentioned in the comments, C++11 is required for this to work.






        share|improve this answer














        As mentioned in the comments, the example from the core guidelines uses user-defined literals to construct application-specific types that intuitively represent physical quantities. To illustrate them for the specific example, consider these types:



        /* "Strong" speed type, unit is always [m/s]. */
        struct Speed
        long double value;
        ;

        /* "Strong" length type, parameterized by a unit as multiples of [m]. */
        template <class Period = std::ratio<1>> struct Length
        unsigned long long value;
        ;


        It probably doesn't make much sense to track the unit of Length objects, but not for Speed instances, but let's consider the simplest possible example here. Now, let's look at two user-defined literals:



        #include <ratio>

        auto operator ""_m(unsigned long long n)

        return Length<>n;


        auto operator ""_km(unsigned long long n)

        return Length<std::kilo>n;



        They let you instantiate Length objects like this:



        /* We use auto here, because the suffix is so crystal clear: */
        const auto lengthInMeter = 23_m;
        const auto lengthInKilometer = 23_km;


        In order to cosntruct a Speed instance, let's define an appropriate operator for dividing a Length by a duration:



        #include <chrono>

        template <class LengthRatio, class Rep, class DurationRatio>
        auto operator / (const Length<LengthRatio>& lhs,
        const std::chrono::duration<Rep, DurationRatio>& rhs)

        const auto lengthFactor = static_cast<double>(LengthRatio::num)/LengthRatio::den;
        const auto rhsInSeconds = std::chrono::duration_cast<std::chrono::seconds>(rhs);

        return SpeedlengthFactor*lhs.value/rhsInSeconds.count();



        Now, let's look at the example from the core guidelines again,



        void change_speed(const Speed& s)

        /* Complicated stuff... */



        but most importantly, how you can call such a function:



        using namespace std::chrono_literals;

        int main(int, char **)

        change_speed(23_m/1s);
        change_speed(42_km/3600s);
        change_speed(42_km/1h);

        return 0;



        As @KillzoneKid mentioned in the comments, C++11 is required for this to work.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Aug 21 at 8:32

























        answered Aug 21 at 8:01









        lubgr

        7,08521441




        7,08521441






















            up vote
            3
            down vote













            There are two different things involved in your code:



            1. The use of strong/unit types to make your code more robust, i.e., you differentiate two integer types. This is built-in in some languages (e.g., Ada), but not in C++, but you can create classes that wraps integer types to mimic such behavior (see below).


            2. The use of operator literals to create instances of such classes in user-friendly way, i.e., you write 1s instead of seconds1. This is simply a convenience feature, which can be useful in some places.


            Using strong integer types is very useful because it makes your code much less error prone*:



            • You cannot convert between types representing durations and lengths, as in real life.

            • Within types representing the same kind of things (e.g., seconds and hours), there are not implicit conversions if you lose precision, e.g., you cannot convert seconds to hours, unless you are representing our with floating point type (float / double).

            • The (implicit and non-implicit) conversions takes care of the scaling for you: you can convert hours to seconds without having to manually multiply by 3600.

            • You can provide realistic operators that will takes care of conversions for you, e.g., in your example, there is division operator between length and duration that gives speeds. The exact type of speed is automatically deduced from the type of the length and the type of duration:

            auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.


            • Unit types are self-documented: If a function returns microseconds, you know what this is, you do not have to hope that the guy documenting the function returning unsigned long long mentioned that this represents microseconds...

            * I am only talking about implicit conversion here, of course, you can do conversion explicitly, e.g., using duration_cast (loss of precision).




            Unit types



            Wrapping integer types in "unit" classes has always been available, but C++11 brought one standard wrapped integer type: std::chrono::duration.



            A "unit" class can be defined by:



            • the type of thing it represents: time, length, weight, speed, ...

            • the C++ type it uses to represent these data: int, double, ...

            • the ratio between this type and the "1-type" of the same unit.

            Currently, only duration-like types are provided by the standard, but there have been discussion (maybe a proposal?) for providing a more generic basic unit type such as:



            template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;


            ...where Unit would be a placeholder indicating the kind of thing represented, e.g.:



            struct length_t ;

            template <class Rep, class Ratio = std::ratio<1>>
            using length = unit<length_t, Rep, Ratio>;


            But this is not standard yet, so let's have a look at std::chrono::duration:



            template <class Rep, class Period = std::ratio<1>> class duration;


            The Rep template parameters is the C++ type:



            • Standard defined durations types have integer representations (implementation defined).

            • The underlying type defines the type of conversions that can be implicitly made:

              • You can convert integer hours to integer seconds implicitly (multiply by 3600).

              • You can convert integer seconds to integer hours implicitly because you would lose precision.

              • You can convert integer seconds to double hours.


            The Period template parameters defines the ratio between the duration type and one second (which is the basic duration chosen):




            • std::ratio is a very convenient standard-defined type that simply represent a ratio between two integers, with corresponding operations (*, /, ...).

            • The standad provides multiple duration types with various ratios: std::chrono::seconds, std::chrono::minutes, ...


            Operator literals



            These have been introduced in C++11 and are literals operators.



            The s one is standard and is included in the chrono standard library:



            using namespace std::chrono_literals;
            auto one_second = 1s;
            auto one_hour = 1h;


            The m one is not standard, and thus should be prefixed by _ (since it is user-defined), like 23_m. You can define your own operator like so:



            constexpr auto operator "" _m(unsigned long long ull) 
            return metersull;






            share|improve this answer




















            • Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
              – Oliv
              Aug 21 at 16:41










            • @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
              – Holt
              Aug 21 at 18:56










            • That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
              – Oliv
              Aug 22 at 8:24















            up vote
            3
            down vote













            There are two different things involved in your code:



            1. The use of strong/unit types to make your code more robust, i.e., you differentiate two integer types. This is built-in in some languages (e.g., Ada), but not in C++, but you can create classes that wraps integer types to mimic such behavior (see below).


            2. The use of operator literals to create instances of such classes in user-friendly way, i.e., you write 1s instead of seconds1. This is simply a convenience feature, which can be useful in some places.


            Using strong integer types is very useful because it makes your code much less error prone*:



            • You cannot convert between types representing durations and lengths, as in real life.

            • Within types representing the same kind of things (e.g., seconds and hours), there are not implicit conversions if you lose precision, e.g., you cannot convert seconds to hours, unless you are representing our with floating point type (float / double).

            • The (implicit and non-implicit) conversions takes care of the scaling for you: you can convert hours to seconds without having to manually multiply by 3600.

            • You can provide realistic operators that will takes care of conversions for you, e.g., in your example, there is division operator between length and duration that gives speeds. The exact type of speed is automatically deduced from the type of the length and the type of duration:

            auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.


            • Unit types are self-documented: If a function returns microseconds, you know what this is, you do not have to hope that the guy documenting the function returning unsigned long long mentioned that this represents microseconds...

            * I am only talking about implicit conversion here, of course, you can do conversion explicitly, e.g., using duration_cast (loss of precision).




            Unit types



            Wrapping integer types in "unit" classes has always been available, but C++11 brought one standard wrapped integer type: std::chrono::duration.



            A "unit" class can be defined by:



            • the type of thing it represents: time, length, weight, speed, ...

            • the C++ type it uses to represent these data: int, double, ...

            • the ratio between this type and the "1-type" of the same unit.

            Currently, only duration-like types are provided by the standard, but there have been discussion (maybe a proposal?) for providing a more generic basic unit type such as:



            template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;


            ...where Unit would be a placeholder indicating the kind of thing represented, e.g.:



            struct length_t ;

            template <class Rep, class Ratio = std::ratio<1>>
            using length = unit<length_t, Rep, Ratio>;


            But this is not standard yet, so let's have a look at std::chrono::duration:



            template <class Rep, class Period = std::ratio<1>> class duration;


            The Rep template parameters is the C++ type:



            • Standard defined durations types have integer representations (implementation defined).

            • The underlying type defines the type of conversions that can be implicitly made:

              • You can convert integer hours to integer seconds implicitly (multiply by 3600).

              • You can convert integer seconds to integer hours implicitly because you would lose precision.

              • You can convert integer seconds to double hours.


            The Period template parameters defines the ratio between the duration type and one second (which is the basic duration chosen):




            • std::ratio is a very convenient standard-defined type that simply represent a ratio between two integers, with corresponding operations (*, /, ...).

            • The standad provides multiple duration types with various ratios: std::chrono::seconds, std::chrono::minutes, ...


            Operator literals



            These have been introduced in C++11 and are literals operators.



            The s one is standard and is included in the chrono standard library:



            using namespace std::chrono_literals;
            auto one_second = 1s;
            auto one_hour = 1h;


            The m one is not standard, and thus should be prefixed by _ (since it is user-defined), like 23_m. You can define your own operator like so:



            constexpr auto operator "" _m(unsigned long long ull) 
            return metersull;






            share|improve this answer




















            • Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
              – Oliv
              Aug 21 at 16:41










            • @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
              – Holt
              Aug 21 at 18:56










            • That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
              – Oliv
              Aug 22 at 8:24













            up vote
            3
            down vote










            up vote
            3
            down vote









            There are two different things involved in your code:



            1. The use of strong/unit types to make your code more robust, i.e., you differentiate two integer types. This is built-in in some languages (e.g., Ada), but not in C++, but you can create classes that wraps integer types to mimic such behavior (see below).


            2. The use of operator literals to create instances of such classes in user-friendly way, i.e., you write 1s instead of seconds1. This is simply a convenience feature, which can be useful in some places.


            Using strong integer types is very useful because it makes your code much less error prone*:



            • You cannot convert between types representing durations and lengths, as in real life.

            • Within types representing the same kind of things (e.g., seconds and hours), there are not implicit conversions if you lose precision, e.g., you cannot convert seconds to hours, unless you are representing our with floating point type (float / double).

            • The (implicit and non-implicit) conversions takes care of the scaling for you: you can convert hours to seconds without having to manually multiply by 3600.

            • You can provide realistic operators that will takes care of conversions for you, e.g., in your example, there is division operator between length and duration that gives speeds. The exact type of speed is automatically deduced from the type of the length and the type of duration:

            auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.


            • Unit types are self-documented: If a function returns microseconds, you know what this is, you do not have to hope that the guy documenting the function returning unsigned long long mentioned that this represents microseconds...

            * I am only talking about implicit conversion here, of course, you can do conversion explicitly, e.g., using duration_cast (loss of precision).




            Unit types



            Wrapping integer types in "unit" classes has always been available, but C++11 brought one standard wrapped integer type: std::chrono::duration.



            A "unit" class can be defined by:



            • the type of thing it represents: time, length, weight, speed, ...

            • the C++ type it uses to represent these data: int, double, ...

            • the ratio between this type and the "1-type" of the same unit.

            Currently, only duration-like types are provided by the standard, but there have been discussion (maybe a proposal?) for providing a more generic basic unit type such as:



            template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;


            ...where Unit would be a placeholder indicating the kind of thing represented, e.g.:



            struct length_t ;

            template <class Rep, class Ratio = std::ratio<1>>
            using length = unit<length_t, Rep, Ratio>;


            But this is not standard yet, so let's have a look at std::chrono::duration:



            template <class Rep, class Period = std::ratio<1>> class duration;


            The Rep template parameters is the C++ type:



            • Standard defined durations types have integer representations (implementation defined).

            • The underlying type defines the type of conversions that can be implicitly made:

              • You can convert integer hours to integer seconds implicitly (multiply by 3600).

              • You can convert integer seconds to integer hours implicitly because you would lose precision.

              • You can convert integer seconds to double hours.


            The Period template parameters defines the ratio between the duration type and one second (which is the basic duration chosen):




            • std::ratio is a very convenient standard-defined type that simply represent a ratio between two integers, with corresponding operations (*, /, ...).

            • The standad provides multiple duration types with various ratios: std::chrono::seconds, std::chrono::minutes, ...


            Operator literals



            These have been introduced in C++11 and are literals operators.



            The s one is standard and is included in the chrono standard library:



            using namespace std::chrono_literals;
            auto one_second = 1s;
            auto one_hour = 1h;


            The m one is not standard, and thus should be prefixed by _ (since it is user-defined), like 23_m. You can define your own operator like so:



            constexpr auto operator "" _m(unsigned long long ull) 
            return metersull;






            share|improve this answer












            There are two different things involved in your code:



            1. The use of strong/unit types to make your code more robust, i.e., you differentiate two integer types. This is built-in in some languages (e.g., Ada), but not in C++, but you can create classes that wraps integer types to mimic such behavior (see below).


            2. The use of operator literals to create instances of such classes in user-friendly way, i.e., you write 1s instead of seconds1. This is simply a convenience feature, which can be useful in some places.


            Using strong integer types is very useful because it makes your code much less error prone*:



            • You cannot convert between types representing durations and lengths, as in real life.

            • Within types representing the same kind of things (e.g., seconds and hours), there are not implicit conversions if you lose precision, e.g., you cannot convert seconds to hours, unless you are representing our with floating point type (float / double).

            • The (implicit and non-implicit) conversions takes care of the scaling for you: you can convert hours to seconds without having to manually multiply by 3600.

            • You can provide realistic operators that will takes care of conversions for you, e.g., in your example, there is division operator between length and duration that gives speeds. The exact type of speed is automatically deduced from the type of the length and the type of duration:

            auto speed = 70km / 1h; // Don't bother deducing the type of speed, let the compiler do it for you.


            • Unit types are self-documented: If a function returns microseconds, you know what this is, you do not have to hope that the guy documenting the function returning unsigned long long mentioned that this represents microseconds...

            * I am only talking about implicit conversion here, of course, you can do conversion explicitly, e.g., using duration_cast (loss of precision).




            Unit types



            Wrapping integer types in "unit" classes has always been available, but C++11 brought one standard wrapped integer type: std::chrono::duration.



            A "unit" class can be defined by:



            • the type of thing it represents: time, length, weight, speed, ...

            • the C++ type it uses to represent these data: int, double, ...

            • the ratio between this type and the "1-type" of the same unit.

            Currently, only duration-like types are provided by the standard, but there have been discussion (maybe a proposal?) for providing a more generic basic unit type such as:



            template <class Unit, class Rep, class Ratio = std::ratio<1>> class unit;


            ...where Unit would be a placeholder indicating the kind of thing represented, e.g.:



            struct length_t ;

            template <class Rep, class Ratio = std::ratio<1>>
            using length = unit<length_t, Rep, Ratio>;


            But this is not standard yet, so let's have a look at std::chrono::duration:



            template <class Rep, class Period = std::ratio<1>> class duration;


            The Rep template parameters is the C++ type:



            • Standard defined durations types have integer representations (implementation defined).

            • The underlying type defines the type of conversions that can be implicitly made:

              • You can convert integer hours to integer seconds implicitly (multiply by 3600).

              • You can convert integer seconds to integer hours implicitly because you would lose precision.

              • You can convert integer seconds to double hours.


            The Period template parameters defines the ratio between the duration type and one second (which is the basic duration chosen):




            • std::ratio is a very convenient standard-defined type that simply represent a ratio between two integers, with corresponding operations (*, /, ...).

            • The standad provides multiple duration types with various ratios: std::chrono::seconds, std::chrono::minutes, ...


            Operator literals



            These have been introduced in C++11 and are literals operators.



            The s one is standard and is included in the chrono standard library:



            using namespace std::chrono_literals;
            auto one_second = 1s;
            auto one_hour = 1h;


            The m one is not standard, and thus should be prefixed by _ (since it is user-defined), like 23_m. You can define your own operator like so:



            constexpr auto operator "" _m(unsigned long long ull) 
            return metersull;







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Aug 21 at 8:32









            Holt

            24.2k64989




            24.2k64989











            • Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
              – Oliv
              Aug 21 at 16:41










            • @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
              – Holt
              Aug 21 at 18:56










            • That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
              – Oliv
              Aug 22 at 8:24

















            • Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
              – Oliv
              Aug 21 at 16:41










            • @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
              – Holt
              Aug 21 at 18:56










            • That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
              – Oliv
              Aug 22 at 8:24
















            Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
            – Oliv
            Aug 21 at 16:41




            Once we will have units in C++ we will understand how good practice is to perform dimensional analysis and how computing simulation using dimensionless equation is such a good solution! ;)
            – Oliv
            Aug 21 at 16:41












            @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
            – Holt
            Aug 21 at 18:56




            @Oliv It's already quite easy to implements units in C++, especially if you simply wraps a std::chrono::duration. ;)
            – Holt
            Aug 21 at 18:56












            That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
            – Oliv
            Aug 22 at 8:24





            That lacks the concept of Dimension (the Units template parameter), and the possibility to multiply/divide numbers with different dimension: 1 meter / 1 second = 1 meter/second => dimensionaly meter/second = speed. See boost units.
            – Oliv
            Aug 22 at 8:24


















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f51943434%2funits-for-types-in-c%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?