├── .gitignore ├── makefile ├── gdb-pretty-printer.py ├── .travis.yml ├── README.md ├── strong_typedef.hpp └── test_strong_typedef.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | *.obj 3 | *.o 4 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test 2 | 3 | ifeq ($(OS),Windows_NT) 4 | EXE_SUFFIX=.exe 5 | RUN_PREFIX= 6 | else 7 | EXE_SUFFIX= 8 | RUN_PREFIX=./ 9 | endif 10 | 11 | ifeq ($(CXX),cl) 12 | CXXFLAGS=/std:c++17 /EHsc 13 | OUTPUTFLAG=/Fe 14 | else 15 | CXXFLAGS=-std=c++17 -g 16 | OUTPUTFLAG=-o 17 | endif 18 | 19 | TEST_EXE=test_strong_typedef$(EXE_SUFFIX) 20 | 21 | test: $(TEST_EXE) 22 | $(RUN_PREFIX)$(TEST_EXE) 23 | 24 | $(TEST_EXE): test_strong_typedef.cpp strong_typedef.hpp 25 | $(CXX) $(CXXFLAGS) $(OUTPUTFLAG)$@ $< 26 | -------------------------------------------------------------------------------- /gdb-pretty-printer.py: -------------------------------------------------------------------------------- 1 | import gdb.printing 2 | 3 | class StrongTypedefPrinter: 4 | def __init__(self,val): 5 | self.val=val 6 | 7 | def to_string(self): 8 | return "{value=" + str(self.val["value"])+"}" 9 | 10 | def build_pretty_printer(): 11 | pp = gdb.printing.RegexpCollectionPrettyPrinter( 12 | "strong_typedef") 13 | pp.add_printer('strong_typedef', '^jss::strong_typedef<.*>$', StrongTypedefPrinter) 14 | return pp 15 | 16 | gdb.printing.register_pretty_printer( 17 | gdb.current_objfile(), 18 | build_pretty_printer()) 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | script: make test 4 | 5 | matrix: 6 | include: 7 | - os: linux 8 | dist: xenial 9 | compiler: clang 10 | name: "Linux clang 7" 11 | - os: osx 12 | osx_image: xcode10.1 13 | name: "Macos xcode 10.1" 14 | - os: linux 15 | dist: xenial 16 | addons: 17 | apt: 18 | sources: 19 | - ubuntu-toolchain-r-test 20 | packages: 21 | - g++-7 22 | env: 23 | - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" 24 | name: "Linux gcc 7" 25 | - os: linux 26 | dist: xenial 27 | addons: 28 | apt: 29 | sources: 30 | - ubuntu-toolchain-r-test 31 | packages: 32 | - g++-8 33 | env: 34 | - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" 35 | name: "Linux gcc 8" 36 | - os: linux 37 | dist: xenial 38 | addons: 39 | apt: 40 | sources: 41 | - llvm-toolchain-xenial-8 42 | packages: 43 | - clang-8 44 | env: 45 | - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" 46 | name: "Linux clang 8" 47 | 48 | before_install: 49 | - eval "${MATRIX_EVAL}" 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `jss::strong_typedef ` 2 | 3 | [![Build Status](https://travis-ci.com/anthonywilliams/strong_typedef.svg?branch=master)](https://travis-ci.com/anthonywilliams/strong_typedef) 4 | 5 | This is an implementation of a C++17 class template that provides a wrapper type that is convertible to 6 | and from the underlying type, but is distinct from it. 7 | 8 | The purpose of this is primarily to enable things like indexes and IDs to be unique types. This is 9 | achieved by specifying a `Tag` type for each `jss::strong_typedef` use, alongside the `ValueType` 10 | which is being wrapped. This `Tag` type can be an incomplete type, and can be forward-declared in 11 | the template parameter directly. For example: 12 | 13 | ~~~cplusplus 14 | #include "strong_typedef.hpp" 15 | 16 | using FirstIndex=jss::strong_typedef; 17 | using SecondIndex=jss::strong_typedef; 18 | ~~~ 19 | 20 | `FirstIndex` and `SecondIndex` are both explicitly convertible to/from `int`, but they are separate 21 | types and are thus not inter-convertible. They also have no additional operations beyond retrieving 22 | the underlying value, as no properties are specified. 23 | 24 | The third template parameter (`Properties...`) is an optional parameter pack that specifies the 25 | operations you wish the strong typedef to support. By default it is empty, so no operations are 26 | supported. See [below](#properties) for a full list. 27 | 28 | ### Declaring Types 29 | 30 | You create a typedef by specifying these parameters: 31 | 32 | ~~~cplusplus 33 | using type1=jss::strong_typedef; 34 | using type2=jss::strong_typedef; 35 | using type3=jss::strong_typedef; 37 | ~~~ 38 | 39 | `type1`, `type2` and `type3` are now separate types. They cannot be implicitly converted 40 | to or from each other or anything else. 41 | 42 | ### Creating Values 43 | 44 | If the underlying type is default-constructible, then so is the new type. You 45 | can also construct the objects from an object of the wrapped type: 46 | 47 | ~~~cplusplus 48 | type1 t1; 49 | type2 t2(42); 50 | // type2 e2(t1); // error, type1 cannot be converted to type2 51 | ~~~ 52 | 53 | ### Accessing the Value 54 | 55 | `strong_typedef` can wrap built-in or class type, but that's only useful if you 56 | can access the value. There are two ways to access the value: 57 | 58 | * Cast to the stored type: `static_cast(my_channel_index)` 59 | * Use the `underlying_value` member function: `my_channel_index.underlying_value()` 60 | 61 | Using the `underlying_value` member function returns a reference to the stored 62 | value, which can thus be used to modify non-`const` values, or to call member 63 | functions on the stored value without taking a copy. This makes it particularly 64 | useful for class types such as `std::string`. 65 | 66 | ~~~cplusplus 67 | using transaction_id=jss::strong_typedef; 68 | 69 | bool is_a_foo(transaction_id id){ 70 | auto &s= id.underlying_value(); 71 | return s.find("foo") != s.end(); 72 | } 73 | ~~~ 74 | 75 | ### Other Operations 76 | 77 | Depending on the [properties](#properties) you've assigned to your type you may 78 | be able to do other operations on that type, such as compare `a == b` or 79 | `a < b`, increment with `++a`, or add two values with `a + b`. You might also be 80 | able to hash the values with `std::hash`, or write them to a 81 | `std::ostream` with `os << a`. Only the behaviours enabled by the `Properties` 82 | template parameter will be available on any given type. For anything else, you 83 | need to extract the wrapped value and use that. 84 | 85 | ## Examples 86 | 87 | ### IDs 88 | 89 | An ID of some description might essentially be a number, but it makes no sense 90 | to perform much in the way of operations on it. You probably want to be able to 91 | compare IDs, possibly with an ordering so you can use them as keys in a 92 | `std::map`, or with hashing so you can use them as keys in `std::unordered_map`, 93 | and maybe you want to be able to write them to a stream. Such an ID type might 94 | be declared as follows: 95 | 96 | ~~~cplusplus 97 | using widget_id=jss::strong_typedef; 101 | 102 | using froob_id=jss::strong_typedef; 106 | ~~~ 107 | 108 | Note that `froob_id` and `widget_id` are now different types due to the 109 | different tags used, even though they are both based on `unsigned long 110 | long`. Therefore any attempt to use a `widget_id` as a `froob_id` or vice-versa 111 | will lead to a compiler error. It also means you can overload on them: 112 | 113 | ~~~cplusplus 114 | void do_stuff(widget_id my_widget); 115 | void do_stuff(froob_id my_froob); 116 | 117 | widget_id some_widget(421982); 118 | do_stuff(some_widget); 119 | ~~~ 120 | 121 | Alternatively, an ID might be a string, such as a purchase order number of 122 | transaction ID: 123 | 124 | ~~~cplusplus 125 | using transaction_id=jss::strong_typedef; 129 | 130 | transaction_id some_transaction("GBA283-HT9X"); 131 | ~~~ 132 | 133 | That works too, since `strong_typedef` can wrap any built-in or class type. 134 | 135 | ### Indexes 136 | 137 | Suppose you have a device that supports a number of channels, so you want to be 138 | able to retrieve the data for a given channel. Each channel yields a number of 139 | data items, so you also want to access the data items by index. You could use 140 | `strong_typedef` to wrap the channel index and the data item index, so they 141 | can't be confused. You can also make the index types `incrementable` and 142 | `decrementable` so they can be used in a `for` loop: 143 | 144 | ~~~cplusplus 145 | using channel_index=jss::strong_typedef; 149 | 150 | using data_index=jss::strong_typedef; 154 | 155 | Data get_data_item(channel_index channel,data_index item); 156 | data_index get_num_items(channel_index channel); 157 | void process_data(Data data); 158 | 159 | void foo(){ 160 | channel_index const num_channels(99); 161 | for(channel_index channel(0); channel < num_channels; ++channel) { 162 | data_index const num_data_items(get_num_items(channel)); 163 | for(data_index item(0); item < num_data_items; ++item) { 164 | process_data(get_data_item(channel, item)); 165 | } 166 | } 167 | } 168 | ~~~ 169 | 170 | The compiler will complain if you pass the wrong parameters, or compare the 171 | `channel` against the `item`. 172 | 173 | ## Behaviour Properties 174 | 175 | The third template parameter (`Properties...`) specifies behavioural properties for the new type. It 176 | can be any combination of the types in the `jss::strong_typedef_properties` namespace, 177 | (e.g. `jss::strong_typedef_properties::hashable, jss::strong_typedef_properties::streamable, 178 | jss::strong_typedef_properties::comparable`). Each property adds some behaviour. The available 179 | properties are: 180 | 181 | * `jss::strong_typedef_properties::equality_comparable` => Can be compared for equality (`st==st2`) 182 | and inequality (`st!=st2`) 183 | * `jss::strong_typedef_properties::pre_incrementable` => Supports preincrement (`++st`) 184 | * `jss::strong_typedef_properties::post_incrementable` => Supports postincrement (`st++`) 185 | * `jss::strong_typedef_properties::pre_decrementable` => Supports predecrement (`--st`) 186 | * `jss::strong_typedef_properties::post_decrementable` => Supports postdecrement (`st--`) 187 | * `jss::strong_typedef_properties::self_addable` => Supports addition of two objects of the strong 188 | typedef (`st+st2`) where the result is convertible to the underlying type. The result is a new 189 | instance of the strong typedef. 190 | * `jss::strong_typedef_properties::mixed_addable` => Supports addition of an object of the strong 191 | typedef with another object of type `T` either way round (`st+value` or `value+st`) where the 192 | result is convertible to the underlying type. The result is a new instance of the strong typedef. 193 | * `jss::strong_typedef_properties::addable` => Combines `self_addable` and 194 | `mixed_addable` 195 | * `jss::strong_typedef_properties::generic_mixed_addable` => Supports addition of an object of the 196 | strong typedef with another object of any type either way round (`st+value` or `value+st`) where 197 | the result is convertible to the underlying type. The result is a new instance of the strong 198 | typedef. 199 | * `jss::strong_typedef_properties::self_subtractable` => Supports subtraction of two objects of the 200 | strong typedef (`st-st2`) where the result is convertible to the underlying type. The result is a 201 | new instance of the strong typedef. 202 | * `jss::strong_typedef_properties::mixed_subtractable` => Supports subtraction of an object of 203 | the strong typedef with another object of type `T` either way round (`st-value` or `value-st`) 204 | where the result is convertible to the underlying type. The result is a new instance of the strong 205 | typedef. 206 | * `jss::strong_typedef_properties::generic_mixed_subtractable` => Supports subtraction of an object 207 | of the strong typedef with another object of any type either way round (`st-value` or `value-st`) 208 | where the result is convertible to the underlying type. The result is a new instance of the strong 209 | typedef. 210 | * `jss::strong_typedef_properties::subtractable` => Combines `self_subtractable` and 211 | `mixed_subtractable` 212 | * `jss::strong_typedef_properties::difference` => Supports subtraction of two objects of the 213 | strong typedef (`st-st2`) where the result is convertible to `T`. The result is an object of type `T`. 214 | * `jss::strong_typedef_properties::self_multiplicable` => Supports multiplication of two objects of 215 | the strong typedef (`st*st2`) where the result is convertible to the underlying type. The result 216 | is a new instance of the strong typedef. 217 | * `jss::strong_typedef_properties::mixed_multiplicable` => Supports multiplication of an object 218 | of the strong typedef with another object of type `T` either way round (`st*value` or `value*st`) 219 | where the result is convertible to the underlying type. The result is a new instance of the strong 220 | typedef. 221 | * `jss::strong_typedef_properties::multiplicable` => Combines `self_multiplicable` and 222 | `mixed_multiplicable` 223 | * `jss::strong_typedef_properties::self_divisible` => Supports division of two objects of the strong 224 | typedef (`st/st2`) where the result is convertible to the underlying type. The result is a new 225 | instance of the strong typedef. 226 | * `jss::strong_typedef_properties::mixed_divisible` => Supports division of an object of the 227 | strong typedef with another object of type `T` either way round (`st/value` or `value/st`) where 228 | the result is convertible to the underlying type. The result is a new instance of the strong 229 | typedef. 230 | * `jss::strong_typedef_properties::divisible` => Combines `self_divisible` and 231 | `mixed_divisible` 232 | * `jss::strong_typedef_properties::self_modulus` => Supports modulus operations on two objects of the strong 233 | typedef (`st%st2`) where the result is convertible to the underlying type. The result is a new 234 | instance of the strong typedef. 235 | * `jss::strong_typedef_properties::mixed_modulus` => Supports modulus operations on an object of 236 | the strong typedef with another object of type `T` either way round (`st%value` or `value%st`) 237 | where the result is convertible to the underlying type. The result is a new instance of the strong 238 | typedef. 239 | * `jss::strong_typedef_properties::modulus` => Combines `self_modulus` and 240 | `mixed_modulus` 241 | * `jss::strong_typedef_properties::ratio` => Supports division of two objects of the strong 242 | typedef (`st/st2`) where the result is convertible to `T`. The result is an object of type `T`. 243 | * `jss::strong_typedef_properties::ordered` => Supports ordering comparisons (`stst2`, 244 | `st<=st2`, `st>=st2`) 245 | * `jss::strong_typedef_properties::mixed_ordered` => Supports ordering comparisons where only one 246 | of the values is a strong typedef and the other is `T` 247 | * `jss::strong_typedef_properties::self_bitwise_or` => Supports bitwise or of two objects of the 248 | strong typedef (`st|st2`) where the result is convertible to the underlying type. The result is a 249 | new instance of the strong typedef. 250 | * `jss::strong_typedef_properties::mixed_bitwise_or` => Supports bitwise or of an object of the 251 | strong typedef with another object of type `T` either way round (`st|value` or `value|st`) where 252 | the result is convertible to the underlying type. The result is a new instance of the strong 253 | typedef. 254 | * `jss::strong_typedef_properties::bitwise_or` => Combines `self_bitwise_or` and 255 | `mixed_bitwise_or` 256 | * `jss::strong_typedef_properties::self_bitwise_xor` => Supports bitwise xor of two objects of the 257 | strong typedef (`st^st2`) where the result is convertible to the underlying type. The result is a 258 | new instance of the strong typedef. 259 | * `jss::strong_typedef_properties::mixed_bitwise_xor` => Supports bitwise xor of an object of the 260 | strong typedef with another object of type `T` either way round (`st^value` or `value^st`) where 261 | the result is convertible to the underlying type. The result is a new instance of the strong 262 | typedef. 263 | * `jss::strong_typedef_properties::bitwise_xor` => Combines `self_bitwise_xor` and 264 | `mixed_bitwise_xor` 265 | * `jss::strong_typedef_properties::self_bitwise_and` => Supports bitwise and of two objects of the 266 | strong typedef (`st&st2`) where the result is convertible to the underlying type. The result is a 267 | new instance of the strong typedef. 268 | * `jss::strong_typedef_properties::mixed_bitwise_and` => Supports bitwise and of an object of the 269 | strong typedef with another object of type `T` either way round (`st&value` or `value&st`) where 270 | the result is convertible to the underlying type. The result is a new instance of the strong 271 | typedef. 272 | * `jss::strong_typedef_properties::bitwise_and` => Combines `self_bitwise_and` and 273 | `mixed_bitwise_and` 274 | * `jss::strong_typedef_properties::bitwise_left_shift` => Supports bitwise left shift of an 275 | object of the strong typedef by the value another object of type `T` (`st<` => Supports bitwise right shift of an 278 | object of the strong typedef by the value another object of type `T` (`st>>value`) where the 279 | result is convertible to the underlying type. The result is a new instance of the strong typedef. 280 | * `jss::strong_typedef_properties::hashable` => Supports hashing with `std::hash` 281 | * `jss::strong_typedef_properties::streamable` => Can be written to a `std::ostream` with 282 | `operator<<` 283 | * `jss::strong_typedef_properties::incrementable` => Combines 284 | `jss::strong_typedef_properties::pre_incrementable` and 285 | `jss::strong_typedef_properties::post_incrementable` 286 | * `jss::strong_typedef_properties::decrementable` => Combines 287 | `jss::strong_typedef_properties::pre_decrementable` and 288 | `jss::strong_typedef_properties::post_decrementable` 289 | * `jss::strong_typedef_properties::comparable` => Combines `jss::strong_typedef_properties::ordered` 290 | and `jss::strong_typedef_properties::equality_comparable` 291 | 292 | For operators where `st op rhs` yields an instance of the strong typedef, `st op= rhs` is also 293 | defined as `st.underlying_value() op= rhs`. 294 | 295 | ## Writing new properties 296 | 297 | You can write a new property by creating a class with the following structure: 298 | 299 | ~~~cplusplus 300 | struct my_property{ 301 | template struct mixin {}; 302 | }; 303 | ~~~ 304 | 305 | Each strong typedef that uses the new property (e.g. `jss::strong_typedef Boost Software License - Version 1.0 - August 17th, 2003 318 | > 319 | > Permission is hereby granted, free of charge, to any person or organization 320 | > obtaining a copy of the software and accompanying documentation covered by 321 | > this license (the "Software") to use, reproduce, display, distribute, 322 | > execute, and transmit the Software, and to prepare derivative works of the 323 | > Software, and to permit third-parties to whom the Software is furnished to 324 | > do so, all subject to the following: 325 | > 326 | > The copyright notices in the Software and this entire statement, including 327 | > the above license grant, this restriction and the following disclaimer, 328 | > must be included in all copies of the Software, in whole or in part, and 329 | > all derivative works of the Software, unless such copies or derivative 330 | > works are solely in the form of machine-executable object code generated by 331 | > a source language processor. 332 | > 333 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 334 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 335 | > FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 336 | > SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 337 | > FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 338 | > ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 339 | > DEALINGS IN THE SOFTWARE. 340 | -------------------------------------------------------------------------------- /strong_typedef.hpp: -------------------------------------------------------------------------------- 1 | #ifndef JSS_STRONG_TYPEDEF_HPP 2 | #define JSS_STRONG_TYPEDEF_HPP 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace jss { 9 | /// Internal implementation namespace 10 | namespace detail { 11 | /// A small type used for operation tests 12 | using small_result= char; 13 | /// A large type with a different size to the small type, used for 14 | /// operation tests 15 | struct large_result { 16 | small_result dummy[2]; 17 | }; 18 | 19 | } // namespace detail 20 | 21 | /// The strong_typedef template used to create unique types with 22 | /// specific properties. 23 | /// 24 | /// Tag is a tag type used for uniqueness. It can be incomplete as 25 | /// it is never used for anything except creating unique template 26 | /// instantiations 27 | /// 28 | /// ValueType is the type this Strong typedef is based on: it is the type of 29 | /// the underlying value 30 | /// 31 | /// Properties are types that provide mixins that enable certain operations 32 | /// on values of this type. 33 | template 34 | class strong_typedef 35 | : public Properties::template mixin< 36 | strong_typedef, ValueType>... { 37 | public: 38 | /// The underlying value type 39 | using underlying_value_type= ValueType; 40 | 41 | /// A default constructed strong_typedef has a default-constructed value 42 | constexpr strong_typedef() noexcept : value() {} 43 | 44 | /// Construct a strong_typedef holding the specified value 45 | explicit constexpr strong_typedef(ValueType value_) noexcept( 46 | std::is_nothrow_move_constructible::value) : 47 | value(std::move(value_)) {} 48 | 49 | /// Explicit conversion operator to read the underlying value 50 | explicit constexpr operator ValueType const &() const noexcept { 51 | return value; 52 | } 53 | 54 | /// Get a const reference to the underlying value 55 | constexpr ValueType const &underlying_value() const noexcept { 56 | return value; 57 | } 58 | 59 | /// Get a reference to the underlying value 60 | constexpr ValueType &underlying_value() noexcept { 61 | return value; 62 | } 63 | 64 | /// Get a reference to the underlying value 65 | friend constexpr ValueType &underlying_value(strong_typedef &t) { 66 | return t.underlying_value(); 67 | } 68 | 69 | /// Get a const reference to the underlying value 70 | friend constexpr ValueType const & 71 | underlying_value(strong_typedef const &t) { 72 | return t.underlying_value(); 73 | } 74 | 75 | /// Get a const rvalue reference to the underlying value 76 | friend constexpr ValueType &&underlying_value(strong_typedef &&t) { 77 | return std::move(t.underlying_value()); 78 | } 79 | 80 | /// Get an rvalue reference to the underlying value 81 | friend constexpr ValueType const && 82 | underlying_value(strong_typedef const &&t) { 83 | return std::move(t.underlying_value()); 84 | } 85 | 86 | private: 87 | /// The underlying value 88 | ValueType value; 89 | }; 90 | 91 | /// The underlying value of a value that is not a strong_typedef is just 92 | /// that value 93 | template constexpr T &&underlying_value(T &&t) { 94 | return std::forward(t); 95 | } 96 | 97 | /// Namespace to wrap the property types 98 | namespace strong_typedef_properties { 99 | /// Add operator== and operator!= to the strong_typedef 100 | struct equality_comparable { 101 | template struct mixin { 102 | friend constexpr bool 103 | operator==(Derived const &lhs, Derived const &rhs) noexcept( 104 | noexcept( 105 | std::declval() == 106 | std::declval())) { 107 | return lhs.underlying_value() == rhs.underlying_value(); 108 | } 109 | friend constexpr bool 110 | operator!=(Derived const &lhs, Derived const &rhs) noexcept( 111 | noexcept( 112 | std::declval() != 113 | std::declval())) { 114 | return lhs.underlying_value() != rhs.underlying_value(); 115 | } 116 | }; 117 | }; 118 | 119 | /// Add the preincrement operator to the strong_typedef 120 | struct pre_incrementable { 121 | template struct mixin { 122 | friend Derived &operator++(Derived &self) noexcept( 123 | noexcept(++std::declval())) { 124 | ++self.underlying_value(); 125 | return self; 126 | } 127 | }; 128 | }; 129 | 130 | /// Add the post-increment operator to the strong_typedef 131 | struct post_incrementable { 132 | template struct mixin { 133 | friend Derived operator++(Derived &self, int) noexcept( 134 | noexcept(std::declval()++)) { 135 | return Derived{self.underlying_value()++}; 136 | } 137 | }; 138 | }; 139 | 140 | /// Add both pre- and post-increment operators to the strong_typedef 141 | struct incrementable { 142 | template 143 | struct mixin : pre_incrementable::mixin, 144 | post_incrementable::mixin {}; 145 | }; 146 | 147 | /// Add the pre-decrement operator to the strong_typedef 148 | struct pre_decrementable { 149 | template struct mixin { 150 | friend Derived &operator--(Derived &self) noexcept( 151 | noexcept(--std::declval())) { 152 | --self.underlying_value(); 153 | return self; 154 | } 155 | }; 156 | }; 157 | 158 | /// Add the post-decrement operator to the strong_typedef 159 | struct post_decrementable { 160 | template struct mixin { 161 | friend Derived operator--(Derived &self, int) noexcept( 162 | noexcept(std::declval()--)) { 163 | return Derived{self.underlying_value()--}; 164 | } 165 | }; 166 | }; 167 | 168 | /// Add both pre- and post-decrement operators to the strong_typedef 169 | struct decrementable { 170 | template 171 | struct mixin : pre_decrementable::mixin, 172 | post_decrementable::mixin {}; 173 | }; 174 | 175 | /// Add operator+ that supports adding the strong_typedef to anything 176 | /// the underlying value can be added to 177 | struct generic_mixed_addable { 178 | template struct mixin { 179 | template 180 | friend typename std::enable_if< 181 | !std::is_same::value && 182 | std::is_convertible< 183 | decltype( 184 | std::declval() + 185 | underlying_value(std::declval())), 186 | ValueType>::value, 187 | Derived>::type 188 | operator+(Derived const &lhs, Rhs const &rhs) noexcept(noexcept( 189 | std::declval() + 190 | underlying_value(std::declval()))) { 191 | return Derived{lhs.underlying_value() + 192 | underlying_value(rhs)}; 193 | } 194 | 195 | template 196 | friend typename std::enable_if< 197 | !std::is_same::value && 198 | std::is_convertible< 199 | decltype( 200 | underlying_value(std::declval()) + 201 | std::declval()), 202 | ValueType>::value, 203 | Derived>::type 204 | operator+(Lhs const &lhs, Derived const &rhs) noexcept(noexcept( 205 | underlying_value(std::declval()) + 206 | std::declval())) { 207 | return Derived{underlying_value(lhs) + 208 | rhs.underlying_value()}; 209 | } 210 | }; 211 | }; 212 | #define JSS_COMPOUND_ASSIGN(op_symbol) op_symbol##= 213 | 214 | #define JSS_DEFINE_OP_MIXINS(name, op_symbol) \ 215 | /** Add operator op_symbol to the strong_typedef **/ \ 216 | template struct mixed_##name { \ 217 | template < \ 218 | typename Derived, typename ValueType, \ 219 | bool= std::is_literal_type::value> \ 220 | struct mixin { \ 221 | friend constexpr Derived \ 222 | operator op_symbol(Derived const &lhs, Other const &rhs) noexcept( \ 223 | noexcept(std::declval() \ 224 | op_symbol underlying_value( \ 225 | std::declval()))) { \ 226 | return Derived{lhs.underlying_value() \ 227 | op_symbol underlying_value(rhs)}; \ 228 | } \ 229 | \ 230 | friend constexpr Derived \ 231 | operator op_symbol(Other const &lhs, Derived const &rhs) noexcept( \ 232 | noexcept(underlying_value(std::declval()) \ 233 | op_symbol std::declval())) { \ 234 | return Derived{underlying_value(lhs) \ 235 | op_symbol rhs.underlying_value()}; \ 236 | } \ 237 | \ 238 | friend Derived &operator JSS_COMPOUND_ASSIGN(op_symbol)( \ 239 | Derived &lhs, \ 240 | Other const \ 241 | &rhs) noexcept(noexcept(std::declval() \ 242 | JSS_COMPOUND_ASSIGN(op_symbol) \ 243 | underlying_value( \ 244 | std::declval< \ 245 | Other const \ 246 | &>()))) { \ 247 | lhs.underlying_value() JSS_COMPOUND_ASSIGN(op_symbol) \ 248 | underlying_value(rhs); \ 249 | return lhs; \ 250 | } \ 251 | }; \ 252 | }; \ 253 | template \ 254 | template \ 255 | struct mixed_##name::mixin { \ 256 | friend Derived \ 257 | operator op_symbol(Derived const &lhs, Other const &rhs) noexcept( \ 258 | noexcept(std::declval() \ 259 | op_symbol underlying_value( \ 260 | std::declval()))) { \ 261 | return Derived{lhs.underlying_value() \ 262 | op_symbol underlying_value(rhs)}; \ 263 | } \ 264 | \ 265 | friend Derived \ 266 | operator op_symbol(Other const &lhs, Derived const &rhs) noexcept( \ 267 | noexcept(underlying_value(std::declval()) \ 268 | op_symbol std::declval())) { \ 269 | return Derived{underlying_value(lhs) \ 270 | op_symbol rhs.underlying_value()}; \ 271 | } \ 272 | \ 273 | friend Derived &operator JSS_COMPOUND_ASSIGN(op_symbol)( \ 274 | Derived &lhs, \ 275 | Other const \ 276 | &rhs) noexcept(noexcept(std::declval() \ 277 | JSS_COMPOUND_ASSIGN(op_symbol) \ 278 | underlying_value( \ 279 | std::declval< \ 280 | Other const &>()))) { \ 281 | lhs.underlying_value() JSS_COMPOUND_ASSIGN(op_symbol) \ 282 | underlying_value(rhs); \ 283 | return lhs; \ 284 | } \ 285 | }; \ 286 | struct self_##name { \ 287 | template < \ 288 | typename Derived, typename ValueType, \ 289 | bool= std::is_literal_type::value> \ 290 | struct mixin { \ 291 | friend constexpr Derived operator op_symbol( \ 292 | Derived const &lhs, \ 293 | Derived const \ 294 | &rhs) noexcept(noexcept(std::declval() \ 295 | op_symbol std::declval< \ 296 | ValueType const &>())) { \ 297 | return Derived{lhs.underlying_value() \ 298 | op_symbol rhs.underlying_value()}; \ 299 | } \ 300 | friend Derived &operator JSS_COMPOUND_ASSIGN(op_symbol)( \ 301 | Derived &lhs, \ 302 | Derived const \ 303 | &rhs) noexcept(noexcept(std::declval() \ 304 | JSS_COMPOUND_ASSIGN(op_symbol) \ 305 | std::declval< \ 306 | ValueType const \ 307 | &>())) { \ 308 | lhs.underlying_value() JSS_COMPOUND_ASSIGN(op_symbol) \ 309 | rhs.underlying_value(); \ 310 | return lhs; \ 311 | } \ 312 | }; \ 313 | }; \ 314 | \ 315 | template \ 316 | struct self_##name::mixin { \ 317 | friend Derived \ 318 | operator op_symbol(Derived const &lhs, Derived const &rhs) noexcept( \ 319 | noexcept(std::declval() \ 320 | op_symbol std::declval())) { \ 321 | return Derived{lhs.underlying_value() \ 322 | op_symbol rhs.underlying_value()}; \ 323 | } \ 324 | friend Derived &operator JSS_COMPOUND_ASSIGN(op_symbol)( \ 325 | Derived &lhs, \ 326 | Derived const \ 327 | &rhs) noexcept(noexcept(std::declval() \ 328 | JSS_COMPOUND_ASSIGN(op_symbol) \ 329 | std::declval< \ 330 | ValueType const &>())) { \ 331 | lhs.underlying_value() JSS_COMPOUND_ASSIGN(op_symbol) \ 332 | rhs.underlying_value(); \ 333 | return lhs; \ 334 | } \ 335 | }; \ 336 | struct name { \ 337 | template \ 338 | struct mixin \ 339 | : self_##name::mixin, \ 340 | mixed_##name::template mixin {}; \ 341 | }; 342 | 343 | /// Define mixins for the built-in operators 344 | /// 345 | /// self_xxx provides the operation where both LHS and RHS are 346 | /// the strong_typedef 347 | /// 348 | /// mixed_xxx provides the operation where only the LHS or RHS 349 | /// is the strong_typedef and the other operand is of type Other 350 | /// 351 | /// xxx combines self_xxx and mixed_xxx 352 | /// 353 | JSS_DEFINE_OP_MIXINS(addable, +) 354 | JSS_DEFINE_OP_MIXINS(subtractable, -) 355 | JSS_DEFINE_OP_MIXINS(multiplicable, *) 356 | JSS_DEFINE_OP_MIXINS(divisible, /) 357 | JSS_DEFINE_OP_MIXINS(modulus, %) 358 | JSS_DEFINE_OP_MIXINS(bitwise_or, |) 359 | JSS_DEFINE_OP_MIXINS(bitwise_and, &) 360 | JSS_DEFINE_OP_MIXINS(bitwise_xor, ^) 361 | 362 | /// Allow subtraction with any type that can be subtracted from the 363 | /// underlying value, or the underlying value can be subtracted from 364 | struct generic_mixed_subtractable { 365 | template struct mixin { 366 | template 367 | friend typename std::enable_if< 368 | !std::is_same::value && 369 | std::is_convertible< 370 | decltype( 371 | std::declval() - 372 | underlying_value(std::declval())), 373 | ValueType>::value, 374 | Derived>::type 375 | operator-(Derived const &lhs, Rhs const &rhs) noexcept(noexcept( 376 | std::declval() - 377 | underlying_value(std::declval()))) { 378 | return Derived{lhs.underlying_value() - 379 | underlying_value(rhs)}; 380 | } 381 | 382 | template 383 | friend typename std::enable_if< 384 | !std::is_same::value && 385 | std::is_convertible< 386 | decltype( 387 | underlying_value(std::declval()) - 388 | std::declval()), 389 | ValueType>::value, 390 | Derived>::type 391 | operator-(Lhs const &lhs, Derived const &rhs) noexcept(noexcept( 392 | underlying_value(std::declval()) - 393 | std::declval())) { 394 | return Derived{underlying_value(lhs) - 395 | rhs.underlying_value()}; 396 | } 397 | }; 398 | }; 399 | 400 | /// Allow subtracting two strong_typedef instances to produce 401 | /// a DifferenceType value tha represents the difference 402 | template struct difference { 403 | template struct mixin { 404 | friend DifferenceType 405 | operator-(Derived const &lhs, Derived const &rhs) noexcept( 406 | noexcept( 407 | std::declval() - 408 | std::declval())) { 409 | return DifferenceType{lhs.underlying_value() - 410 | rhs.underlying_value()}; 411 | } 412 | }; 413 | }; 414 | 415 | /// Add ordering comparison operators to the strong_typedef 416 | struct ordered { 417 | template struct mixin { 418 | friend constexpr bool 419 | operator<(Derived const &lhs, Derived const &rhs) noexcept( 420 | noexcept( 421 | std::declval() < 422 | std::declval())) { 423 | return lhs.underlying_value() < rhs.underlying_value(); 424 | } 425 | friend constexpr bool 426 | operator>(Derived const &lhs, Derived const &rhs) noexcept( 427 | noexcept( 428 | std::declval() > 429 | std::declval())) { 430 | return lhs.underlying_value() > rhs.underlying_value(); 431 | } 432 | friend constexpr bool 433 | operator<=(Derived const &lhs, Derived const &rhs) noexcept( 434 | noexcept( 435 | std::declval() <= 436 | std::declval())) { 437 | return lhs.underlying_value() <= rhs.underlying_value(); 438 | } 439 | friend constexpr bool 440 | operator>=(Derived const &lhs, Derived const &rhs) noexcept( 441 | noexcept( 442 | std::declval() >= 443 | std::declval())) { 444 | return lhs.underlying_value() >= rhs.underlying_value(); 445 | } 446 | }; 447 | }; 448 | 449 | /// Add ordering comparisons to the strong_typedef where the 450 | /// other operand is of type Other 451 | template struct mixed_ordered { 452 | template struct mixin { 453 | friend typename std::enable_if< 454 | !std::is_same::value && 455 | std::is_convertible< 456 | decltype( 457 | std::declval() < 458 | underlying_value( 459 | std::declval())), 460 | bool>::value, 461 | bool>::type 462 | operator<(Derived const &lhs, Other const &rhs) noexcept( 463 | noexcept( 464 | std::declval() < 465 | underlying_value(std::declval()))) { 466 | return lhs.underlying_value() < underlying_value(rhs); 467 | } 468 | 469 | friend typename std::enable_if< 470 | !std::is_same::value && 471 | std::is_convertible< 472 | decltype( 473 | underlying_value( 474 | std::declval()) < 475 | std::declval()), 476 | bool>::value, 477 | bool>::type 478 | operator<(Other const &lhs, Derived const &rhs) noexcept( 479 | noexcept( 480 | underlying_value(std::declval()) < 481 | std::declval())) { 482 | return underlying_value(lhs) < rhs.underlying_value(); 483 | } 484 | 485 | friend typename std::enable_if< 486 | !std::is_same::value && 487 | std::is_convertible< 488 | decltype( 489 | std::declval() > 490 | underlying_value( 491 | std::declval())), 492 | bool>::value, 493 | bool>::type 494 | operator>(Derived const &lhs, Other const &rhs) noexcept( 495 | noexcept( 496 | std::declval() > 497 | underlying_value(std::declval()))) { 498 | return lhs.underlying_value() > underlying_value(rhs); 499 | } 500 | 501 | friend typename std::enable_if< 502 | !std::is_same::value && 503 | std::is_convertible< 504 | decltype( 505 | underlying_value( 506 | std::declval()) > 507 | std::declval()), 508 | bool>::value, 509 | bool>::type 510 | operator>(Other const &lhs, Derived const &rhs) noexcept( 511 | noexcept( 512 | underlying_value(std::declval()) > 513 | std::declval())) { 514 | return underlying_value(lhs) > rhs.underlying_value(); 515 | } 516 | 517 | friend typename std::enable_if< 518 | !std::is_same::value && 519 | std::is_convertible< 520 | decltype( 521 | std::declval() >= 522 | underlying_value( 523 | std::declval())), 524 | bool>::value, 525 | bool>::type 526 | operator>=(Derived const &lhs, Other const &rhs) noexcept( 527 | noexcept( 528 | std::declval() >= 529 | std::declval())) { 530 | return lhs.underlying_value() >= underlying_value(rhs); 531 | } 532 | 533 | friend typename std::enable_if< 534 | !std::is_same::value && 535 | std::is_convertible< 536 | decltype( 537 | underlying_value( 538 | std::declval()) >= 539 | std::declval()), 540 | bool>::value, 541 | bool>::type 542 | operator>=(Other const &lhs, Derived const &rhs) noexcept( 543 | noexcept( 544 | underlying_value(std::declval()) >= 545 | std::declval())) { 546 | return underlying_value(lhs) >= rhs.underlying_value(); 547 | } 548 | 549 | friend typename std::enable_if< 550 | !std::is_same::value && 551 | std::is_convertible< 552 | decltype( 553 | std::declval() <= 554 | underlying_value( 555 | std::declval())), 556 | bool>::value, 557 | bool>::type 558 | operator<=(Derived const &lhs, Other const &rhs) noexcept( 559 | noexcept( 560 | std::declval() <= 561 | underlying_value(std::declval()))) { 562 | return lhs.underlying_value() <= underlying_value(rhs); 563 | } 564 | 565 | friend typename std::enable_if< 566 | !std::is_same::value && 567 | std::is_convertible< 568 | decltype( 569 | underlying_value( 570 | std::declval()) <= 571 | std::declval()), 572 | bool>::value, 573 | bool>::type 574 | operator<=(Other const &lhs, Derived const &rhs) noexcept( 575 | noexcept( 576 | underlying_value(std::declval()) <= 577 | std::declval())) { 578 | return underlying_value(lhs) <= rhs.underlying_value(); 579 | } 580 | }; 581 | }; 582 | 583 | /// Allow this strong_typedef to be used with std::hash 584 | struct hashable { 585 | struct base {}; 586 | template 587 | struct mixin : base {}; 588 | }; 589 | 590 | /// Add a stream operator to write the strong_typedef to a std::ostream 591 | struct streamable { 592 | template struct mixin { 593 | friend std::ostream & 594 | operator<<(std::ostream &os, Derived const &st) { 595 | return os << st.underlying_value(); 596 | } 597 | }; 598 | }; 599 | 600 | /// Combine ordered and equality_comparable 601 | struct comparable { 602 | template 603 | struct mixin 604 | : ordered::template mixin, 605 | equality_comparable::template mixin {}; 606 | }; 607 | 608 | /// Add a division operation to the strong_typedef that 609 | /// produces a RatioType instances representing the result 610 | template struct ratio { 611 | template struct mixin { 612 | friend RatioType 613 | operator/(Derived const &lhs, Derived const &rhs) noexcept( 614 | noexcept( 615 | std::declval() / 616 | std::declval())) { 617 | return RatioType{lhs.underlying_value() / 618 | rhs.underlying_value()}; 619 | } 620 | }; 621 | }; 622 | 623 | /// Add the bitwise not operator to the strong_typedef 624 | struct bitwise_not { 625 | template < 626 | typename Derived, typename ValueType, 627 | bool= std::is_literal_type::value> 628 | struct mixin { 629 | friend constexpr Derived operator~(Derived const &lhs) noexcept( 630 | noexcept(~std::declval())) { 631 | return Derived{~lhs.underlying_value()}; 632 | } 633 | }; 634 | }; 635 | 636 | template 637 | struct bitwise_not::mixin { 638 | friend Derived operator~(Derived const &lhs) noexcept( 639 | noexcept(~std::declval())) { 640 | return Derived{~lhs.underlying_value()}; 641 | } 642 | }; 643 | 644 | /// Add the bitwise left-shift operator to the strong_typedef 645 | template struct bitwise_left_shift { 646 | template < 647 | typename Derived, typename ValueType, 648 | bool= std::is_literal_type::value> 649 | struct mixin { 650 | friend constexpr Derived 651 | operator<<(Derived const &lhs, Other const &rhs) noexcept( 652 | noexcept( 653 | std::declval() 654 | << underlying_value(std::declval()))) { 655 | return Derived{lhs.underlying_value() 656 | << underlying_value(rhs)}; 657 | } 658 | friend Derived & 659 | operator<<=(Derived &lhs, Other const &rhs) noexcept(noexcept( 660 | std::declval()<<= 661 | underlying_value(std::declval()))) { 662 | lhs.underlying_value()<<= underlying_value(rhs); 663 | return lhs; 664 | } 665 | }; 666 | }; 667 | 668 | template 669 | template 670 | struct bitwise_left_shift::mixin { 671 | friend Derived 672 | operator<<(Derived const &lhs, Other const &rhs) noexcept(noexcept( 673 | std::declval() 674 | << underlying_value(std::declval()))) { 675 | return Derived{lhs.underlying_value() << underlying_value(rhs)}; 676 | } 677 | friend Derived & 678 | operator<<=(Derived &lhs, Other const &rhs) noexcept(noexcept( 679 | std::declval()<<= 680 | underlying_value(std::declval()))) { 681 | lhs.underlying_value()<<= underlying_value(rhs); 682 | return lhs; 683 | } 684 | }; 685 | 686 | /// Add the bitwise right-shift operator to the strong_typedef 687 | template struct bitwise_right_shift { 688 | template < 689 | typename Derived, typename ValueType, 690 | bool= std::is_literal_type::value> 691 | struct mixin { 692 | friend constexpr Derived 693 | operator>>(Derived const &lhs, Other const &rhs) noexcept( 694 | noexcept( 695 | std::declval() >> 696 | underlying_value(std::declval()))) { 697 | return Derived{lhs.underlying_value() >> 698 | underlying_value(rhs)}; 699 | } 700 | friend Derived & 701 | operator>>=(Derived &lhs, Other const &rhs) noexcept(noexcept( 702 | std::declval()>>= 703 | underlying_value(std::declval()))) { 704 | lhs.underlying_value()>>= underlying_value(rhs); 705 | return lhs; 706 | } 707 | }; 708 | }; 709 | 710 | template 711 | template 712 | struct bitwise_right_shift::mixin { 713 | friend Derived 714 | operator>>(Derived const &lhs, Other const &rhs) noexcept(noexcept( 715 | std::declval() >> 716 | underlying_value(std::declval()))) { 717 | return Derived{lhs.underlying_value() >> underlying_value(rhs)}; 718 | } 719 | friend Derived & 720 | operator>>=(Derived &lhs, Other const &rhs) noexcept(noexcept( 721 | std::declval()>>= 722 | underlying_value(std::declval()))) { 723 | lhs.underlying_value()>>= underlying_value(rhs); 724 | return lhs; 725 | } 726 | }; 727 | 728 | } // namespace strong_typedef_properties 729 | } // namespace jss 730 | 731 | namespace std { 732 | /// A specialization of std::hash for those instances of strong_typedef that 733 | /// have the hashable property 734 | template 735 | struct hash> { 736 | template 737 | typename std::enable_if< 738 | std::is_same< 739 | Arg, 740 | jss::strong_typedef>::value && 741 | std::is_base_of< 742 | jss::strong_typedef_properties::hashable::base, Arg>::value, 743 | size_t>::type 744 | operator()(Arg const &arg) const noexcept(noexcept( 745 | std::hash()(std::declval()))) { 746 | return std::hash()(arg.underlying_value()); 747 | } 748 | }; 749 | 750 | } // namespace std 751 | 752 | #endif 753 | -------------------------------------------------------------------------------- /test_strong_typedef.cpp: -------------------------------------------------------------------------------- 1 | #include "strong_typedef.hpp" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void test_strong_typedef_is_not_original() { 8 | std::cout << __FUNCTION__ << std::endl; 9 | 10 | static_assert( 11 | !std::is_same>::value, 12 | "Strong typedef should not be the same"); 13 | static_assert( 14 | !std::is_same< 15 | jss::strong_typedef, 16 | jss::strong_typedef>::value, 17 | "Strong typedefs with different tags should not be the same"); 18 | } 19 | 20 | void test_strong_typedef_explicitly_convertible_from_source() { 21 | std::cout << __FUNCTION__ << std::endl; 22 | 23 | jss::strong_typedef st(42); 24 | } 25 | 26 | using ConvTestTypedef= jss::strong_typedef; 27 | 28 | using small_result= char; 29 | struct large_result { 30 | small_result dummy[2]; 31 | }; 32 | 33 | small_result conv_test(ConvTestTypedef); 34 | large_result conv_test(...); 35 | 36 | void test_strong_typedef_not_implicitly_convertible_from_source() { 37 | std::cout << __FUNCTION__ << std::endl; 38 | static_assert(sizeof(conv_test(42)) == sizeof(large_result)); 39 | } 40 | 41 | void test_strong_typedef_explicitly_convertible_to_source() { 42 | std::cout << __FUNCTION__ << std::endl; 43 | 44 | jss::strong_typedef st(42); 45 | assert(static_cast(st) == 42); 46 | } 47 | 48 | small_result conv_test_to_int(int); 49 | large_result conv_test_to_int(...); 50 | 51 | void test_strong_typedef_not_implicitly_convertible_to_source() { 52 | std::cout << __FUNCTION__ << std::endl; 53 | 54 | jss::strong_typedef st(42); 55 | static_assert(sizeof(conv_test_to_int(st)) == sizeof(large_result)); 56 | } 57 | 58 | void test_strong_typedef_is_copyable_and_movable() { 59 | std::cout << __FUNCTION__ << std::endl; 60 | std::string const s= 61 | "hello there this is quote a long string abcdefghijklmnopoq"; 62 | using ST= jss::strong_typedef; 63 | ST st(s); 64 | 65 | static_assert( 66 | std::is_copy_constructible::value, 67 | "strong typedef should be copy constructible"); 68 | static_assert( 69 | std::is_copy_assignable::value, 70 | "strong typedef should be copy assignable"); 71 | static_assert( 72 | std::is_move_constructible::value, 73 | "strong typedef should be move constructible"); 74 | static_assert( 75 | std::is_move_assignable::value, 76 | "strong typedef should be move assignable"); 77 | 78 | ST st2(st); 79 | 80 | assert(static_cast(st) == s); 81 | assert(static_cast(st2) == s); 82 | 83 | ST st3(std::move(st)); 84 | assert(static_cast(st) == ""); 85 | assert(static_cast(st2) == s); 86 | assert(static_cast(st3) == s); 87 | 88 | st= std::move(st2); 89 | assert(static_cast(st) == s); 90 | assert(static_cast(st2) == ""); 91 | assert(static_cast(st3) == s); 92 | 93 | st2= st; 94 | assert(static_cast(st) == s); 95 | assert(static_cast(st2) == s); 96 | assert(static_cast(st3) == s); 97 | } 98 | 99 | template 100 | typename std::enable_if< 101 | sizeof(std::declval() == std::declval()) != 0, 102 | small_result>::type 103 | test_equality(int); 104 | template large_result test_equality(...); 105 | 106 | template 107 | typename std::enable_if< 108 | sizeof(std::declval() != std::declval()) != 0, 109 | small_result>::type 110 | test_inequality(int); 111 | template large_result test_inequality(...); 112 | 113 | void test_by_default_strong_typedef_is_not_equality_comparable() { 114 | std::cout << __FUNCTION__ << std::endl; 115 | 116 | using ST= jss::strong_typedef; 117 | 118 | static_assert(sizeof(test_equality(0)) == sizeof(large_result)); 119 | static_assert( 120 | sizeof(test_equality(0)) == sizeof(small_result)); 121 | static_assert(sizeof(test_inequality(0)) == sizeof(large_result)); 122 | static_assert( 123 | sizeof(test_inequality(0)) == sizeof(small_result)); 124 | } 125 | 126 | void test_can_get_underlying_value_and_type() { 127 | std::cout << __FUNCTION__ << std::endl; 128 | 129 | struct LocalTag; 130 | struct X { 131 | int i; 132 | }; 133 | 134 | using ST= jss::strong_typedef; 135 | 136 | ST st({42}); 137 | 138 | static_assert( 139 | std::is_same::value, 140 | "Strong typedef must expose underlying type"); 141 | static_assert( 142 | std::is_same< 143 | decltype(std::declval().underlying_value()), X &>::value, 144 | "Strong typedef must expose underlying value"); 145 | static_assert( 146 | std::is_same< 147 | decltype(std::declval().underlying_value()), 148 | X const &>::value, 149 | "Strong typedef must expose underlying value"); 150 | assert(st.underlying_value().i == 42); 151 | } 152 | 153 | void test_strong_typedef_is_equality_comparable_if_tagged_as_such() { 154 | std::cout << __FUNCTION__ << std::endl; 155 | 156 | using ST= jss::strong_typedef< 157 | struct Tag, std::string, 158 | jss::strong_typedef_properties::equality_comparable>; 159 | 160 | static_assert(sizeof(test_equality(0)) == sizeof(small_result)); 161 | static_assert( 162 | sizeof(test_equality(0)) == sizeof(small_result)); 163 | static_assert(sizeof(test_inequality(0)) == sizeof(small_result)); 164 | static_assert( 165 | sizeof(test_inequality(0)) == sizeof(small_result)); 166 | } 167 | 168 | template 169 | typename std::enable_if()++) != 0, small_result>::type 170 | test_post_incrementable(int); 171 | template large_result test_post_incrementable(...); 172 | 173 | template 174 | typename std::enable_if()) != 0, small_result>::type 175 | test_pre_incrementable(int); 176 | template large_result test_pre_incrementable(...); 177 | 178 | void test_by_default_strong_typedef_is_not_incrementable() { 179 | std::cout << __FUNCTION__ << std::endl; 180 | 181 | using ST= jss::strong_typedef; 182 | 183 | static_assert( 184 | sizeof(test_post_incrementable(0)) == sizeof(large_result)); 185 | assert( 186 | sizeof(test_post_incrementable(0)) == 187 | sizeof(large_result)); 188 | static_assert( 189 | sizeof(test_post_incrementable(0)) == sizeof(small_result)); 190 | static_assert( 191 | sizeof(test_pre_incrementable(0)) == sizeof(large_result)); 192 | assert( 193 | sizeof(test_pre_incrementable(0)) == sizeof(large_result)); 194 | static_assert( 195 | sizeof(test_pre_incrementable(0)) == sizeof(small_result)); 196 | } 197 | 198 | void test_strong_typedef_is_incrementable_if_tagged_as_such() { 199 | std::cout << __FUNCTION__ << std::endl; 200 | 201 | using ST_post= jss::strong_typedef< 202 | struct Tag, int, jss::strong_typedef_properties::post_incrementable>; 203 | using ST_pre= jss::strong_typedef< 204 | struct Tag, int, jss::strong_typedef_properties::pre_incrementable>; 205 | using ST_both= jss::strong_typedef< 206 | struct ST_both_tag, int, jss::strong_typedef_properties::incrementable>; 207 | 208 | static_assert( 209 | sizeof(test_pre_incrementable(0)) == sizeof(small_result)); 210 | static_assert( 211 | sizeof(test_pre_incrementable(0)) == sizeof(large_result)); 212 | static_assert( 213 | sizeof(test_post_incrementable(0)) == sizeof(large_result)); 214 | static_assert( 215 | sizeof(test_post_incrementable(0)) == sizeof(small_result)); 216 | static_assert( 217 | sizeof(test_pre_incrementable(0)) == sizeof(small_result)); 218 | static_assert( 219 | sizeof(test_post_incrementable(0)) == sizeof(small_result)); 220 | 221 | ST_post post1(42); 222 | ST_post post2= post1++; 223 | 224 | assert(post1.underlying_value() == 43); 225 | assert(post2.underlying_value() == 42); 226 | 227 | ST_pre pre1(42); 228 | ST_pre &pre2= ++pre1; 229 | 230 | assert(&pre2 == &pre1); 231 | 232 | assert(pre1.underlying_value() == 43); 233 | } 234 | 235 | template 236 | typename std::enable_if()--) != 0, small_result>::type 237 | test_post_decrementable(int); 238 | template large_result test_post_decrementable(...); 239 | 240 | template 241 | typename std::enable_if()) != 0, small_result>::type 242 | test_pre_decrementable(int); 243 | template large_result test_pre_decrementable(...); 244 | 245 | void test_by_default_strong_typedef_is_not_decrementable() { 246 | std::cout << __FUNCTION__ << std::endl; 247 | 248 | using ST= jss::strong_typedef; 249 | 250 | static_assert( 251 | sizeof(test_post_decrementable(0)) == sizeof(large_result)); 252 | assert( 253 | sizeof(test_post_decrementable(0)) == 254 | sizeof(large_result)); 255 | static_assert( 256 | sizeof(test_post_decrementable(0)) == sizeof(small_result)); 257 | static_assert( 258 | sizeof(test_pre_decrementable(0)) == sizeof(large_result)); 259 | assert( 260 | sizeof(test_pre_decrementable(0)) == sizeof(large_result)); 261 | static_assert( 262 | sizeof(test_pre_decrementable(0)) == sizeof(small_result)); 263 | } 264 | 265 | void test_strong_typedef_is_decrementable_if_tagged_as_such() { 266 | std::cout << __FUNCTION__ << std::endl; 267 | 268 | using ST_post= jss::strong_typedef< 269 | struct Tag, int, jss::strong_typedef_properties::post_decrementable>; 270 | using ST_pre= jss::strong_typedef< 271 | struct Tag, int, jss::strong_typedef_properties::pre_decrementable>; 272 | 273 | static_assert( 274 | sizeof(test_pre_decrementable(0)) == sizeof(small_result)); 275 | static_assert( 276 | sizeof(test_pre_decrementable(0)) == sizeof(large_result)); 277 | static_assert( 278 | sizeof(test_post_decrementable(0)) == sizeof(large_result)); 279 | static_assert( 280 | sizeof(test_post_decrementable(0)) == sizeof(small_result)); 281 | 282 | ST_post post1(42); 283 | ST_post post2= post1--; 284 | 285 | assert(post1.underlying_value() == 41); 286 | assert(post2.underlying_value() == 42); 287 | 288 | ST_pre pre1(42); 289 | ST_pre &pre2= --pre1; 290 | 291 | assert(&pre2 == &pre1); 292 | 293 | assert(pre1.underlying_value() == 41); 294 | } 295 | 296 | template 297 | typename std::enable_if< 298 | sizeof(std::declval() + std::declval()) != 0, small_result>::type 299 | test_addable(int); 300 | template large_result test_addable(...); 301 | 302 | void test_by_default_strong_typedef_is_not_addable() { 303 | std::cout << __FUNCTION__ << std::endl; 304 | 305 | using ST= jss::strong_typedef; 306 | 307 | static_assert(sizeof(test_addable(0)) == sizeof(large_result)); 308 | static_assert( 309 | sizeof(test_addable(0)) == sizeof(large_result)); 310 | static_assert(sizeof(test_addable(0)) == sizeof(large_result)); 311 | static_assert( 312 | sizeof(test_addable(0)) == sizeof(large_result)); 313 | static_assert(sizeof(test_addable(0)) == sizeof(large_result)); 314 | assert( 315 | sizeof(test_addable(0)) == 316 | sizeof(small_result)); 317 | static_assert(sizeof(test_addable(0)) == sizeof(small_result)); 318 | static_assert( 319 | sizeof(test_addable(0)) == sizeof(large_result)); 320 | } 321 | 322 | void test_strong_typedef_is_addable_if_tagged_as_such() { 323 | std::cout << __FUNCTION__ << std::endl; 324 | 325 | using ST= jss::strong_typedef< 326 | struct Tag, std::string, jss::strong_typedef_properties::addable>; 327 | static_assert(sizeof(test_addable(0)) == sizeof(small_result)); 328 | static_assert( 329 | sizeof(test_addable(0)) == sizeof(small_result)); 330 | static_assert(sizeof(test_addable(0)) == sizeof(large_result)); 331 | static_assert( 332 | sizeof(test_addable(0)) == sizeof(small_result)); 333 | static_assert(sizeof(test_addable(0)) == sizeof(large_result)); 334 | 335 | ST st1("hello"); 336 | ST st2= st1 + " world"; 337 | assert(st1.underlying_value() == "hello"); 338 | assert(st2.underlying_value() == "hello world"); 339 | auto st3= "goodbye" + st1; 340 | assert(st1.underlying_value() == "hello"); 341 | assert(st3.underlying_value() == "goodbyehello"); 342 | auto st4= st1 + st1; 343 | assert(st1.underlying_value() == "hello"); 344 | assert(st4.underlying_value() == "hellohello"); 345 | } 346 | 347 | template 348 | typename std::enable_if< 349 | sizeof(std::declval() - std::declval()) != 0, small_result>::type 350 | test_subtractable(int); 351 | template large_result test_subtractable(...); 352 | 353 | void test_by_default_strong_typedef_is_not_subtractable() { 354 | std::cout << __FUNCTION__ << std::endl; 355 | 356 | using ST= jss::strong_typedef; 357 | 358 | static_assert(sizeof(test_subtractable(0)) == sizeof(large_result)); 359 | assert( 360 | sizeof(test_subtractable(0)) == sizeof(large_result)); 361 | static_assert( 362 | sizeof(test_subtractable(0)) == sizeof(large_result)); 363 | assert( 364 | sizeof(test_subtractable(0)) == sizeof(large_result)); 365 | static_assert( 366 | sizeof(test_subtractable(0)) == sizeof(large_result)); 367 | assert( 368 | sizeof(test_subtractable(0)) == 369 | sizeof(large_result)); 370 | static_assert( 371 | sizeof(test_subtractable(0)) == sizeof(small_result)); 372 | assert( 373 | sizeof(test_subtractable(0)) == sizeof(large_result)); 374 | } 375 | 376 | void test_strong_typedef_is_subtractable_if_tagged_as_such() { 377 | std::cout << __FUNCTION__ << std::endl; 378 | 379 | using ST= jss::strong_typedef< 380 | struct Tag, int, jss::strong_typedef_properties::subtractable>; 381 | static_assert(sizeof(test_subtractable(0)) == sizeof(small_result)); 382 | assert( 383 | sizeof(test_subtractable(0)) == sizeof(large_result)); 384 | static_assert( 385 | sizeof(test_subtractable(0)) == sizeof(small_result)); 386 | assert( 387 | sizeof(test_subtractable(0)) == sizeof(large_result)); 388 | static_assert( 389 | sizeof(test_subtractable(0)) == sizeof(small_result)); 390 | } 391 | 392 | template 393 | typename std::enable_if< 394 | std::is_same< 395 | bool, decltype(std::declval() < std::declval())>:: 396 | value && 397 | std::is_same< 398 | bool, decltype( 399 | std::declval() > 400 | std::declval())>::value && 401 | std::is_same< 402 | bool, decltype( 403 | std::declval() <= 404 | std::declval())>::value && 405 | std::is_same< 406 | bool, 407 | decltype( 408 | std::declval() >= std::declval())>::value, 409 | small_result>::type 410 | test_ordered(int); 411 | template large_result test_ordered(...); 412 | 413 | void test_by_default_strong_typedef_is_not_ordered() { 414 | std::cout << __FUNCTION__ << std::endl; 415 | 416 | using ST= jss::strong_typedef; 417 | 418 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 419 | static_assert( 420 | sizeof(test_ordered(0)) == sizeof(large_result)); 421 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 422 | static_assert( 423 | sizeof(test_ordered(0)) == sizeof(large_result)); 424 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 425 | assert( 426 | sizeof(test_ordered(0)) == 427 | sizeof(small_result)); 428 | static_assert(sizeof(test_ordered(0)) == sizeof(small_result)); 429 | static_assert(sizeof(test_ordered(0)) == sizeof(small_result)); 430 | static_assert( 431 | sizeof(test_ordered(0)) == sizeof(large_result)); 432 | } 433 | 434 | void test_strong_typedef_is_ordered_if_tagged_as_such() { 435 | std::cout << __FUNCTION__ << std::endl; 436 | 437 | using ST= jss::strong_typedef< 438 | struct Tag, int, jss::strong_typedef_properties::ordered>; 439 | using ST2= jss::strong_typedef< 440 | struct Tag2, int, jss::strong_typedef_properties::ordered>; 441 | static_assert(sizeof(test_ordered(0)) == sizeof(small_result)); 442 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 443 | static_assert( 444 | sizeof(test_ordered(0)) == sizeof(large_result)); 445 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 446 | static_assert( 447 | sizeof(test_ordered(0)) == sizeof(large_result)); 448 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 449 | 450 | ST const st1(42); 451 | ST const st2(43); 452 | 453 | assert(!(st1 < st1)); 454 | assert(!(st1 > st1)); 455 | assert(st1 <= st1); 456 | assert(st1 >= st1); 457 | assert(st1 < st2); 458 | assert(st1 <= st2); 459 | assert(!(st2 < st1)); 460 | assert(!(st2 <= st1)); 461 | assert(st2 > st1); 462 | assert(st2 >= st1); 463 | assert(!(st1 > st2)); 464 | assert(!(st1 >= st2)); 465 | } 466 | 467 | void test_strong_typedef_is_mixed_ordered_if_tagged_as_such() { 468 | std::cout << __FUNCTION__ << std::endl; 469 | 470 | using ST= jss::strong_typedef< 471 | struct Tag, int, jss::strong_typedef_properties::mixed_ordered>; 472 | using ST2= jss::strong_typedef< 473 | struct Tag2, int, jss::strong_typedef_properties::mixed_ordered>; 474 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 475 | static_assert(sizeof(test_ordered(0)) == sizeof(large_result)); 476 | static_assert( 477 | sizeof(test_ordered(0)) == sizeof(large_result)); 478 | static_assert(sizeof(test_ordered(0)) == sizeof(small_result)); 479 | static_assert( 480 | sizeof(test_ordered(0)) == sizeof(large_result)); 481 | static_assert(sizeof(test_ordered(0)) == sizeof(small_result)); 482 | 483 | ST constexpr st1(42); 484 | int const st2(43); 485 | 486 | assert(st1 < st2); 487 | assert(st1 <= st2); 488 | assert(!(st2 < st1)); 489 | assert(!(st2 <= st1)); 490 | assert(st2 > st1); 491 | assert(st2 >= st1); 492 | assert(!(st1 > st2)); 493 | assert(!(st1 >= st2)); 494 | } 495 | 496 | template 497 | typename std::enable_if< 498 | std::is_convertible< 499 | decltype(std::hash()(std::declval())), size_t>::value, 500 | small_result>::type 501 | test_hashable(int); 502 | template large_result test_hashable(...); 503 | 504 | void test_by_default_strong_typedef_is_not_hashable() { 505 | std::cout << __FUNCTION__ << std::endl; 506 | 507 | using ST= jss::strong_typedef; 508 | 509 | static_assert(sizeof(test_hashable(0)) == sizeof(large_result)); 510 | static_assert( 511 | sizeof(test_hashable(0)) == sizeof(small_result)); 512 | static_assert(sizeof(test_hashable(0)) == sizeof(small_result)); 513 | } 514 | 515 | void test_strong_typedef_is_hashable_if_tagged_as_such() { 516 | std::cout << __FUNCTION__ << std::endl; 517 | 518 | using ST= jss::strong_typedef< 519 | struct Tag, std::string, jss::strong_typedef_properties::hashable>; 520 | static_assert(sizeof(test_hashable(0)) == sizeof(small_result)); 521 | 522 | std::string s("hello"); 523 | ST st(s); 524 | assert(std::hash()(st) == std::hash()(s)); 525 | } 526 | 527 | template 528 | typename std::enable_if< 529 | std::is_convertible< 530 | decltype(std::declval() << std::declval()), 531 | std::ostream &>::value, 532 | small_result>::type 533 | test_streamable(int); 534 | template large_result test_streamable(...); 535 | 536 | void test_by_default_strong_typedef_is_not_streamable() { 537 | std::cout << __FUNCTION__ << std::endl; 538 | 539 | using ST= jss::strong_typedef; 540 | 541 | static_assert(sizeof(test_streamable(0)) == sizeof(large_result)); 542 | static_assert( 543 | sizeof(test_streamable(0)) == sizeof(small_result)); 544 | static_assert(sizeof(test_streamable(0)) == sizeof(small_result)); 545 | } 546 | 547 | void test_strong_typedef_is_streamable_if_tagged_as_such() { 548 | std::cout << __FUNCTION__ << std::endl; 549 | 550 | using ST= jss::strong_typedef< 551 | struct Tag, std::string, jss::strong_typedef_properties::streamable>; 552 | static_assert( 553 | sizeof(test_streamable(0)) == sizeof(small_result), 554 | "Must be streamable when tagged"); 555 | 556 | std::string s("hello"); 557 | ST st(s); 558 | std::stringstream os; 559 | os << st; 560 | 561 | assert(os.str() == s); 562 | } 563 | 564 | void test_properties_can_be_combined() { 565 | std::cout << __FUNCTION__ << std::endl; 566 | using ST= jss::strong_typedef< 567 | struct Tag, std::string, jss::strong_typedef_properties::streamable, 568 | jss::strong_typedef_properties::hashable, 569 | jss::strong_typedef_properties::comparable>; 570 | static_assert( 571 | sizeof(test_streamable(0)) == sizeof(small_result), 572 | "Must be streamable when tagged"); 573 | static_assert( 574 | sizeof(test_hashable(0)) == sizeof(small_result), 575 | "Must be hashable when tagged"); 576 | static_assert( 577 | sizeof(test_ordered(0)) == sizeof(small_result), 578 | "Must be ordered when tagged"); 579 | static_assert( 580 | sizeof(test_equality(0)) == sizeof(small_result), 581 | "Must be equality-comparable when tagged"); 582 | } 583 | 584 | void test_strong_typedef_is_default_constructible() { 585 | std::cout << __FUNCTION__ << std::endl; 586 | 587 | struct X { 588 | int value; 589 | 590 | X() : value(42) {} 591 | }; 592 | 593 | using ST= jss::strong_typedef; 594 | 595 | ST st; 596 | 597 | assert(static_cast(st).value == 42); 598 | 599 | jss::strong_typedef i; 600 | 601 | assert(static_cast(i) == 0); 602 | } 603 | 604 | void test_can_support_difference_with_other_type() { 605 | std::cout << __FUNCTION__ << std::endl; 606 | 607 | using difference_type= jss::strong_typedef; 608 | using ST= jss::strong_typedef< 609 | struct sometag, int, 610 | jss::strong_typedef_properties::difference>; 611 | 612 | static_assert(sizeof(test_subtractable(0)) == sizeof(small_result)); 613 | static_assert( 614 | std::is_same< 615 | decltype(std::declval() - std::declval()), 616 | difference_type>::value); 617 | 618 | ST st1(45); 619 | ST st2(99); 620 | 621 | difference_type res= st2 - st1; 622 | assert(res.underlying_value() == 54); 623 | } 624 | 625 | template 626 | typename std::enable_if< 627 | sizeof(std::declval() * std::declval()) != 0, small_result>::type 628 | test_multiplicable(int); 629 | template large_result test_multiplicable(...); 630 | 631 | void test_self_multiplication() { 632 | std::cout << __FUNCTION__ << std::endl; 633 | 634 | static_assert( 635 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 636 | 637 | using ST1= jss::strong_typedef; 638 | static_assert( 639 | sizeof(test_multiplicable(0)) == sizeof(large_result)); 640 | static_assert( 641 | sizeof(test_multiplicable(0)) == sizeof(large_result)); 642 | static_assert( 643 | sizeof(test_multiplicable(0)) == sizeof(large_result)); 644 | } 645 | 646 | void test_mixed_multiplication() { 647 | std::cout << __FUNCTION__ << std::endl; 648 | 649 | using ST2= jss::strong_typedef< 650 | struct Tag2, int, jss::strong_typedef_properties::self_multiplicable>; 651 | static_assert( 652 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 653 | static_assert( 654 | sizeof(test_multiplicable(0)) == sizeof(large_result)); 655 | static_assert( 656 | sizeof(test_multiplicable(0)) == sizeof(large_result)); 657 | 658 | ST2 a(5); 659 | ST2 b(6); 660 | ST2 c= a * b; 661 | assert(c.underlying_value() == 30); 662 | 663 | using ST3= jss::strong_typedef< 664 | struct Tag3, int, 665 | jss::strong_typedef_properties::mixed_multiplicable>; 666 | static_assert( 667 | sizeof(test_multiplicable(0)) == sizeof(large_result)); 668 | static_assert( 669 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 670 | static_assert( 671 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 672 | 673 | ST3 d(9); 674 | int e(7); 675 | ST3 f= d * e; 676 | assert(f.underlying_value() == 63); 677 | 678 | using ST4= jss::strong_typedef< 679 | struct Tag4, int, jss::strong_typedef_properties::multiplicable>; 680 | static_assert( 681 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 682 | static_assert( 683 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 684 | static_assert( 685 | sizeof(test_multiplicable(0)) == sizeof(small_result)); 686 | } 687 | 688 | template 689 | typename std::enable_if< 690 | sizeof(std::declval() / std::declval()) != 0, small_result>::type 691 | test_divisible(int); 692 | template large_result test_divisible(...); 693 | 694 | void test_self_division() { 695 | std::cout << __FUNCTION__ << std::endl; 696 | 697 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 698 | 699 | using ST1= jss::strong_typedef; 700 | static_assert(sizeof(test_divisible(0)) == sizeof(large_result)); 701 | static_assert(sizeof(test_divisible(0)) == sizeof(large_result)); 702 | static_assert(sizeof(test_divisible(0)) == sizeof(large_result)); 703 | } 704 | 705 | void test_mixed_division() { 706 | std::cout << __FUNCTION__ << std::endl; 707 | 708 | using ST2= jss::strong_typedef< 709 | struct Tag2, int, jss::strong_typedef_properties::self_divisible>; 710 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 711 | static_assert(sizeof(test_divisible(0)) == sizeof(large_result)); 712 | static_assert(sizeof(test_divisible(0)) == sizeof(large_result)); 713 | 714 | ST2 a(42); 715 | ST2 b(6); 716 | ST2 c= a / b; 717 | assert(c.underlying_value() == 7); 718 | 719 | using ST3= jss::strong_typedef< 720 | struct Tag3, int, jss::strong_typedef_properties::mixed_divisible>; 721 | static_assert(sizeof(test_divisible(0)) == sizeof(large_result)); 722 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 723 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 724 | 725 | ST3 d(99); 726 | int e(11); 727 | ST3 f= d / e; 728 | assert(f.underlying_value() == 9); 729 | 730 | using ST4= jss::strong_typedef< 731 | struct Tag4, int, jss::strong_typedef_properties::divisible>; 732 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 733 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 734 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 735 | } 736 | 737 | template 738 | typename std::enable_if< 739 | sizeof(std::declval() % std::declval()) != 0, small_result>::type 740 | test_modulus(int); 741 | template large_result test_modulus(...); 742 | 743 | void test_self_modulus() { 744 | std::cout << __FUNCTION__ << std::endl; 745 | 746 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 747 | 748 | using ST1= jss::strong_typedef; 749 | static_assert(sizeof(test_modulus(0)) == sizeof(large_result)); 750 | static_assert(sizeof(test_modulus(0)) == sizeof(large_result)); 751 | static_assert(sizeof(test_modulus(0)) == sizeof(large_result)); 752 | } 753 | 754 | void test_mixed_modulus() { 755 | std::cout << __FUNCTION__ << std::endl; 756 | 757 | using ST2= jss::strong_typedef< 758 | struct Tag2, int, jss::strong_typedef_properties::self_modulus>; 759 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 760 | static_assert(sizeof(test_modulus(0)) == sizeof(large_result)); 761 | static_assert(sizeof(test_modulus(0)) == sizeof(large_result)); 762 | 763 | constexpr ST2 a(42); 764 | constexpr ST2 b(5); 765 | constexpr ST2 c= a % b; 766 | static_assert(c.underlying_value() == 2); 767 | 768 | using ST3= jss::strong_typedef< 769 | struct Tag3, int, jss::strong_typedef_properties::mixed_modulus>; 770 | static_assert(sizeof(test_modulus(0)) == sizeof(large_result)); 771 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 772 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 773 | 774 | constexpr ST3 d(99); 775 | constexpr int e(8); 776 | constexpr ST3 f= d % e; 777 | static_assert(f.underlying_value() == 3); 778 | 779 | using ST4= jss::strong_typedef< 780 | struct Tag4, int, jss::strong_typedef_properties::modulus>; 781 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 782 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 783 | static_assert(sizeof(test_modulus(0)) == sizeof(small_result)); 784 | } 785 | 786 | void test_ratio() { 787 | std::cout << __FUNCTION__ << std::endl; 788 | 789 | using ratio_type= jss::strong_typedef; 790 | using ST= jss::strong_typedef< 791 | struct sometag, int, jss::strong_typedef_properties::ratio>; 792 | 793 | static_assert(sizeof(test_divisible(0)) == sizeof(small_result)); 794 | static_assert( 795 | std::is_same< 796 | decltype(std::declval() / std::declval()), 797 | ratio_type>::value); 798 | 799 | ST st1(125); 800 | ST st2(5); 801 | 802 | ratio_type res= st1 / st2; 803 | assert(res.underlying_value() == 25); 804 | } 805 | 806 | void test_constexpr_comparison() { 807 | std::cout << __FUNCTION__ << std::endl; 808 | using ST= jss::strong_typedef< 809 | struct Tag, int, jss::strong_typedef_properties::comparable>; 810 | 811 | constexpr ST st1(42); 812 | constexpr ST st2(43); 813 | constexpr bool r1= st1 == st2; 814 | constexpr bool r2= st1 < st2; 815 | constexpr bool r3= st1 > st2; 816 | constexpr bool r4= st1 <= st2; 817 | constexpr bool r5= st1 >= st2; 818 | constexpr bool r6= st1 != st2; 819 | static_assert(!r1); 820 | static_assert(r2); 821 | static_assert(!r3); 822 | static_assert(r4); 823 | static_assert(!r5); 824 | static_assert(r6); 825 | } 826 | 827 | void test_constexpr_addition() { 828 | std::cout << __FUNCTION__ << std::endl; 829 | using ST= jss::strong_typedef< 830 | struct Tag, int, jss::strong_typedef_properties::addable>; 831 | 832 | constexpr ST st1(42); 833 | constexpr ST st2(3); 834 | 835 | constexpr ST st3= st1 + st2; 836 | constexpr ST st4= st1 + 1; 837 | constexpr ST st5= -1 + st1; 838 | 839 | static_assert(st3.underlying_value() == 45); 840 | static_assert(st4.underlying_value() == 43); 841 | static_assert(st5.underlying_value() == 41); 842 | } 843 | 844 | void test_constexpr_subtraction() { 845 | std::cout << __FUNCTION__ << std::endl; 846 | using ST= jss::strong_typedef< 847 | struct Tag, int, jss::strong_typedef_properties::subtractable>; 848 | 849 | constexpr ST st1(42); 850 | constexpr ST st2(3); 851 | 852 | constexpr ST st3= st1 - st2; 853 | constexpr ST st4= st1 - 1; 854 | constexpr ST st5= -1 - st1; 855 | 856 | static_assert(st3.underlying_value() == 39); 857 | static_assert(st4.underlying_value() == 41); 858 | static_assert(st5.underlying_value() == -43); 859 | } 860 | 861 | template 862 | typename std::enable_if< 863 | sizeof(std::declval() | std::declval()) != 0, small_result>::type 864 | test_bitwise_or(int); 865 | template large_result test_bitwise_or(...); 866 | 867 | void test_bitwise_or() { 868 | std::cout << __FUNCTION__ << std::endl; 869 | 870 | using ST_plain= jss::strong_typedef; 871 | using ST_self= jss::strong_typedef< 872 | struct Self, int, jss::strong_typedef_properties::self_bitwise_or>; 873 | using ST_mixed= jss::strong_typedef< 874 | struct Mixed, int, 875 | jss::strong_typedef_properties::mixed_bitwise_or>; 876 | 877 | static_assert( 878 | sizeof(test_bitwise_or(0)) == sizeof(large_result)); 879 | static_assert( 880 | sizeof(test_bitwise_or(0)) == sizeof(large_result)); 881 | static_assert( 882 | sizeof(test_bitwise_or(0)) == sizeof(large_result)); 883 | 884 | static_assert( 885 | sizeof(test_bitwise_or(0)) == sizeof(small_result)); 886 | static_assert( 887 | sizeof(test_bitwise_or(0)) == sizeof(large_result)); 888 | static_assert( 889 | sizeof(test_bitwise_or(0)) == sizeof(large_result)); 890 | 891 | static_assert( 892 | sizeof(test_bitwise_or(0)) == sizeof(large_result)); 893 | static_assert( 894 | sizeof(test_bitwise_or(0)) == sizeof(small_result)); 895 | static_assert( 896 | sizeof(test_bitwise_or(0)) == sizeof(small_result)); 897 | 898 | constexpr ST_self st1{0x1842}; 899 | constexpr ST_self st2(0x8214); 900 | 901 | constexpr ST_self st3= st1 | st2; 902 | 903 | static_assert(st3.underlying_value() == 0x9a56); 904 | 905 | constexpr ST_mixed st4{0x1842a5}; 906 | constexpr int i1(0x82145a); 907 | 908 | constexpr ST_mixed st5= st4 | i1; 909 | constexpr ST_mixed st6= i1 | st4; 910 | 911 | static_assert(st5.underlying_value() == 0x9a56ff); 912 | static_assert(st6.underlying_value() == 0x9a56ff); 913 | } 914 | 915 | template 916 | typename std::enable_if< 917 | sizeof(std::declval() & std::declval()) != 0, small_result>::type 918 | test_bitwise_and(int); 919 | template large_result test_bitwise_and(...); 920 | 921 | void test_bitwise_and() { 922 | std::cout << __FUNCTION__ << std::endl; 923 | 924 | using ST_plain= jss::strong_typedef; 925 | using ST_self= jss::strong_typedef< 926 | struct Self, int, jss::strong_typedef_properties::self_bitwise_and>; 927 | using ST_mixed= jss::strong_typedef< 928 | struct Mixed, int, 929 | jss::strong_typedef_properties::mixed_bitwise_and>; 930 | 931 | static_assert( 932 | sizeof(test_bitwise_and(0)) == 933 | sizeof(large_result)); 934 | static_assert( 935 | sizeof(test_bitwise_and(0)) == sizeof(large_result)); 936 | static_assert( 937 | sizeof(test_bitwise_and(0)) == sizeof(large_result)); 938 | 939 | static_assert( 940 | sizeof(test_bitwise_and(0)) == sizeof(small_result)); 941 | static_assert( 942 | sizeof(test_bitwise_and(0)) == sizeof(large_result)); 943 | static_assert( 944 | sizeof(test_bitwise_and(0)) == sizeof(large_result)); 945 | 946 | static_assert( 947 | sizeof(test_bitwise_and(0)) == 948 | sizeof(large_result)); 949 | static_assert( 950 | sizeof(test_bitwise_and(0)) == sizeof(small_result)); 951 | static_assert( 952 | sizeof(test_bitwise_and(0)) == sizeof(small_result)); 953 | 954 | constexpr ST_self st1{0x1876}; 955 | constexpr ST_self st2(0x9af4); 956 | 957 | constexpr ST_self st3= st1 & st2; 958 | 959 | static_assert(st3.underlying_value() == 0x1874); 960 | 961 | constexpr ST_mixed st4{0xf3c5a5}; 962 | constexpr int i1(0x83945a); 963 | 964 | constexpr ST_mixed st5= st4 & i1; 965 | constexpr ST_mixed st6= i1 & st4; 966 | 967 | static_assert(st5.underlying_value() == 0x838400); 968 | static_assert(st6.underlying_value() == 0x838400); 969 | } 970 | template 971 | typename std::enable_if< 972 | sizeof(std::declval() ^ std::declval()) != 0, small_result>::type 973 | test_bitwise_xor(int); 974 | template large_result test_bitwise_xor(...); 975 | 976 | void test_bitwise_xor() { 977 | std::cout << __FUNCTION__ << std::endl; 978 | 979 | using ST_plain= jss::strong_typedef; 980 | using ST_self= jss::strong_typedef< 981 | struct Self, int, jss::strong_typedef_properties::self_bitwise_xor>; 982 | using ST_mixed= jss::strong_typedef< 983 | struct Mixed, int, 984 | jss::strong_typedef_properties::mixed_bitwise_xor>; 985 | 986 | static_assert( 987 | sizeof(test_bitwise_xor(0)) == 988 | sizeof(large_result)); 989 | static_assert( 990 | sizeof(test_bitwise_xor(0)) == sizeof(large_result)); 991 | static_assert( 992 | sizeof(test_bitwise_xor(0)) == sizeof(large_result)); 993 | 994 | static_assert( 995 | sizeof(test_bitwise_xor(0)) == sizeof(small_result)); 996 | static_assert( 997 | sizeof(test_bitwise_xor(0)) == sizeof(large_result)); 998 | static_assert( 999 | sizeof(test_bitwise_xor(0)) == sizeof(large_result)); 1000 | 1001 | static_assert( 1002 | sizeof(test_bitwise_xor(0)) == 1003 | sizeof(large_result)); 1004 | static_assert( 1005 | sizeof(test_bitwise_xor(0)) == sizeof(small_result)); 1006 | static_assert( 1007 | sizeof(test_bitwise_xor(0)) == sizeof(small_result)); 1008 | 1009 | constexpr ST_self st1{0x1876}; 1010 | constexpr ST_self st2(0x9af4); 1011 | 1012 | constexpr ST_self st3= st1 ^ st2; 1013 | 1014 | static_assert(st3.underlying_value() == 0x8282); 1015 | 1016 | constexpr ST_mixed st4{0xf3c5a5}; 1017 | constexpr int i1(0x83945a); 1018 | 1019 | constexpr ST_mixed st5= st4 ^ i1; 1020 | constexpr ST_mixed st6= i1 ^ st4; 1021 | 1022 | static_assert(st5.underlying_value() == 0x7051ff); 1023 | static_assert(st6.underlying_value() == 0x7051ff); 1024 | } 1025 | 1026 | template 1027 | typename std::enable_if()) != 0, small_result>::type 1028 | test_bitwise_not(int); 1029 | template large_result test_bitwise_not(...); 1030 | 1031 | void test_bitwise_not() { 1032 | std::cout << __FUNCTION__ << std::endl; 1033 | 1034 | using ST_plain= jss::strong_typedef; 1035 | using ST_self= jss::strong_typedef< 1036 | struct Self, int, jss::strong_typedef_properties::bitwise_not>; 1037 | 1038 | static_assert( 1039 | sizeof(test_bitwise_not(0)) == sizeof(large_result)); 1040 | 1041 | static_assert(sizeof(test_bitwise_not(0)) == sizeof(small_result)); 1042 | 1043 | constexpr ST_self st1{0x1876}; 1044 | 1045 | constexpr ST_self st2= ~st1; 1046 | 1047 | static_assert(st2.underlying_value() == 0xffffe789); 1048 | } 1049 | 1050 | template 1051 | typename std::enable_if< 1052 | sizeof(std::declval() << std::declval()) != 0, small_result>::type 1053 | test_bitwise_left_shift(int); 1054 | template large_result test_bitwise_left_shift(...); 1055 | 1056 | void test_bitwise_left_shift() { 1057 | std::cout << __FUNCTION__ << std::endl; 1058 | 1059 | using ST_plain= jss::strong_typedef; 1060 | using ST_mixed= jss::strong_typedef< 1061 | struct Mixed, int, 1062 | jss::strong_typedef_properties::bitwise_left_shift>; 1063 | 1064 | static_assert( 1065 | sizeof(test_bitwise_left_shift(0)) == 1066 | sizeof(large_result)); 1067 | static_assert( 1068 | sizeof(test_bitwise_left_shift(0)) == 1069 | sizeof(large_result)); 1070 | static_assert( 1071 | sizeof(test_bitwise_left_shift(0)) == 1072 | sizeof(large_result)); 1073 | 1074 | static_assert( 1075 | sizeof(test_bitwise_left_shift(0)) == 1076 | sizeof(large_result)); 1077 | static_assert( 1078 | sizeof(test_bitwise_left_shift(0)) == 1079 | sizeof(small_result)); 1080 | static_assert( 1081 | sizeof(test_bitwise_left_shift(0)) == 1082 | sizeof(large_result)); 1083 | 1084 | constexpr ST_mixed st4{0x1842a5}; 1085 | constexpr int i1(3); 1086 | 1087 | constexpr ST_mixed st5= st4 << i1; 1088 | 1089 | static_assert(st5.underlying_value() == (st4.underlying_value() << i1)); 1090 | } 1091 | 1092 | template 1093 | typename std::enable_if< 1094 | sizeof(std::declval() >> std::declval()) != 0, small_result>::type 1095 | test_bitwise_right_shift(int); 1096 | template large_result test_bitwise_right_shift(...); 1097 | 1098 | void test_bitwise_right_shift() { 1099 | std::cout << __FUNCTION__ << std::endl; 1100 | 1101 | using ST_plain= jss::strong_typedef; 1102 | using ST_mixed= jss::strong_typedef< 1103 | struct Mixed, int, 1104 | jss::strong_typedef_properties::bitwise_right_shift>; 1105 | 1106 | static_assert( 1107 | sizeof(test_bitwise_right_shift(0)) == 1108 | sizeof(large_result)); 1109 | static_assert( 1110 | sizeof(test_bitwise_right_shift(0)) == 1111 | sizeof(large_result)); 1112 | static_assert( 1113 | sizeof(test_bitwise_right_shift(0)) == 1114 | sizeof(large_result)); 1115 | 1116 | static_assert( 1117 | sizeof(test_bitwise_right_shift(0)) == 1118 | sizeof(large_result)); 1119 | static_assert( 1120 | sizeof(test_bitwise_right_shift(0)) == 1121 | sizeof(small_result)); 1122 | static_assert( 1123 | sizeof(test_bitwise_right_shift(0)) == 1124 | sizeof(large_result)); 1125 | 1126 | constexpr ST_mixed st4{0x1842a5}; 1127 | constexpr int i1(3); 1128 | 1129 | constexpr ST_mixed st5= st4 >> i1; 1130 | 1131 | static_assert(st5.underlying_value() == (st4.underlying_value() >> i1)); 1132 | } 1133 | 1134 | template 1135 | typename std::enable_if< 1136 | sizeof(std::declval()+= std::declval()) != 0, small_result>::type 1137 | test_plus_equals(int); 1138 | template large_result test_plus_equals(...); 1139 | 1140 | template 1141 | typename std::enable_if< 1142 | sizeof(std::declval()-= std::declval()) != 0, small_result>::type 1143 | test_minus_equals(int); 1144 | template large_result test_minus_equals(...); 1145 | 1146 | template 1147 | typename std::enable_if< 1148 | sizeof(std::declval()*= std::declval()) != 0, small_result>::type 1149 | test_multiply_equals(int); 1150 | template large_result test_multiply_equals(...); 1151 | 1152 | template 1153 | typename std::enable_if< 1154 | sizeof(std::declval()/= std::declval()) != 0, small_result>::type 1155 | test_divide_equals(int); 1156 | template large_result test_divide_equals(...); 1157 | 1158 | template 1159 | typename std::enable_if< 1160 | sizeof(std::declval()<<= std::declval()) != 0, small_result>::type 1161 | test_left_shift_equals(int); 1162 | template large_result test_left_shift_equals(...); 1163 | 1164 | template 1165 | typename std::enable_if< 1166 | sizeof(std::declval()>>= std::declval()) != 0, small_result>::type 1167 | test_right_shift_equals(int); 1168 | template large_result test_right_shift_equals(...); 1169 | 1170 | template 1171 | typename std::enable_if< 1172 | sizeof(std::declval()%= std::declval()) != 0, small_result>::type 1173 | test_mod_equals(int); 1174 | template large_result test_mod_equals(...); 1175 | 1176 | template 1177 | typename std::enable_if< 1178 | sizeof(std::declval()|= std::declval()) != 0, small_result>::type 1179 | test_bit_or_equals(int); 1180 | template large_result test_bit_or_equals(...); 1181 | 1182 | template 1183 | typename std::enable_if< 1184 | sizeof(std::declval()&= std::declval()) != 0, small_result>::type 1185 | test_bit_and_equals(int); 1186 | template large_result test_bit_and_equals(...); 1187 | 1188 | template 1189 | typename std::enable_if< 1190 | sizeof(std::declval()^= std::declval()) != 0, small_result>::type 1191 | test_bit_xor_equals(int); 1192 | template large_result test_bit_xor_equals(...); 1193 | 1194 | void test_compound_assignment() { 1195 | std::cout << __FUNCTION__ << std::endl; 1196 | 1197 | using ST_plain= jss::strong_typedef; 1198 | using ST_compound_add= jss::strong_typedef< 1199 | struct compound_add, int, jss::strong_typedef_properties::addable>; 1200 | using ST_compound_sub= jss::strong_typedef< 1201 | struct compound_sub, int, jss::strong_typedef_properties::subtractable>; 1202 | using ST_compound_both= jss::strong_typedef< 1203 | struct compound_sub, int, jss::strong_typedef_properties::subtractable, 1204 | jss::strong_typedef_properties::addable>; 1205 | using ST_compound_self_mult= jss::strong_typedef< 1206 | struct compound_self_mult, int, 1207 | jss::strong_typedef_properties::self_multiplicable>; 1208 | using ST_compound_other_mult= jss::strong_typedef< 1209 | struct compound_other_mult, int, 1210 | jss::strong_typedef_properties::mixed_multiplicable>; 1211 | using ST_compound_self_divide= jss::strong_typedef< 1212 | struct compound_self_divide, int, 1213 | jss::strong_typedef_properties::self_divisible>; 1214 | using ST_compound_other_divide= jss::strong_typedef< 1215 | struct compound_other_divide, int, 1216 | jss::strong_typedef_properties::mixed_divisible>; 1217 | using ST_compound_ratio= jss::strong_typedef< 1218 | struct compound_ratio, int, jss::strong_typedef_properties::ratio>; 1219 | using ST_compound_self_mod= jss::strong_typedef< 1220 | struct compound_self_mod, int, 1221 | jss::strong_typedef_properties::self_modulus>; 1222 | using ST_compound_other_mod= jss::strong_typedef< 1223 | struct compound_other_mod, int, 1224 | jss::strong_typedef_properties::mixed_modulus>; 1225 | using ST_compound_self_xor= jss::strong_typedef< 1226 | struct compound_self_xor, int, 1227 | jss::strong_typedef_properties::self_bitwise_xor>; 1228 | using ST_compound_other_xor= jss::strong_typedef< 1229 | struct compound_other_xor, int, 1230 | jss::strong_typedef_properties::mixed_bitwise_xor>; 1231 | using ST_compound_self_or= jss::strong_typedef< 1232 | struct compound_self_or, int, 1233 | jss::strong_typedef_properties::self_bitwise_or>; 1234 | using ST_compound_other_or= jss::strong_typedef< 1235 | struct compound_other_or, int, 1236 | jss::strong_typedef_properties::mixed_bitwise_or>; 1237 | using ST_compound_self_and= jss::strong_typedef< 1238 | struct compound_self_and, int, 1239 | jss::strong_typedef_properties::self_bitwise_and>; 1240 | using ST_compound_other_and= jss::strong_typedef< 1241 | struct compound_other_and, int, 1242 | jss::strong_typedef_properties::mixed_bitwise_and>; 1243 | using ST_compound_left_shift= jss::strong_typedef< 1244 | struct compound_left_shift, int, 1245 | jss::strong_typedef_properties::bitwise_left_shift>; 1246 | using ST_compound_right_shift= jss::strong_typedef< 1247 | struct compound_right_shift, int, 1248 | jss::strong_typedef_properties::bitwise_right_shift>; 1249 | 1250 | static_assert( 1251 | sizeof(test_plus_equals(0)) == sizeof(large_result)); 1252 | static_assert( 1253 | sizeof(test_plus_equals(0)) == 1254 | sizeof(small_result)); 1255 | static_assert( 1256 | sizeof(test_plus_equals(0)) == 1257 | sizeof(large_result)); 1258 | static_assert( 1259 | sizeof(test_plus_equals(0)) == 1260 | sizeof(small_result)); 1261 | 1262 | static_assert( 1263 | sizeof(test_plus_equals(0)) == 1264 | sizeof(large_result)); 1265 | static_assert( 1266 | sizeof(test_plus_equals(0)) == 1267 | sizeof(small_result)); 1268 | static_assert( 1269 | sizeof(test_plus_equals(0)) == 1270 | sizeof(large_result)); 1271 | static_assert( 1272 | sizeof(test_plus_equals(0)) == 1273 | sizeof(small_result)); 1274 | 1275 | static_assert( 1276 | sizeof(test_minus_equals(0)) == sizeof(large_result)); 1277 | static_assert( 1278 | sizeof(test_minus_equals(0)) == 1279 | sizeof(large_result)); 1280 | static_assert( 1281 | sizeof(test_minus_equals(0)) == 1282 | sizeof(small_result)); 1283 | static_assert( 1284 | sizeof(test_minus_equals(0)) == 1285 | sizeof(small_result)); 1286 | 1287 | static_assert( 1288 | sizeof(test_minus_equals(0)) == 1289 | sizeof(large_result)); 1290 | static_assert( 1291 | sizeof(test_minus_equals(0)) == 1292 | sizeof(large_result)); 1293 | static_assert( 1294 | sizeof(test_minus_equals(0)) == 1295 | sizeof(small_result)); 1296 | static_assert( 1297 | sizeof(test_minus_equals(0)) == 1298 | sizeof(small_result)); 1299 | 1300 | static_assert( 1301 | sizeof(test_multiply_equals(0)) == sizeof(large_result)); 1302 | static_assert( 1303 | sizeof(test_divide_equals(0)) == sizeof(large_result)); 1304 | static_assert( 1305 | sizeof(test_mod_equals(0)) == sizeof(large_result)); 1306 | static_assert( 1307 | sizeof(test_left_shift_equals(0)) == 1308 | sizeof(large_result)); 1309 | static_assert( 1310 | sizeof(test_right_shift_equals(0)) == 1311 | sizeof(large_result)); 1312 | static_assert( 1313 | sizeof(test_bit_or_equals(0)) == sizeof(large_result)); 1314 | static_assert( 1315 | sizeof(test_bit_and_equals(0)) == sizeof(large_result)); 1316 | static_assert( 1317 | sizeof(test_bit_xor_equals(0)) == sizeof(large_result)); 1318 | 1319 | static_assert( 1320 | sizeof(test_multiply_equals(0)) == 1321 | sizeof(large_result)); 1322 | static_assert( 1323 | sizeof(test_divide_equals(0)) == 1324 | sizeof(large_result)); 1325 | static_assert( 1326 | sizeof(test_mod_equals(0)) == sizeof(large_result)); 1327 | static_assert( 1328 | sizeof(test_left_shift_equals(0)) == 1329 | sizeof(large_result)); 1330 | static_assert( 1331 | sizeof(test_right_shift_equals(0)) == 1332 | sizeof(large_result)); 1333 | static_assert( 1334 | sizeof(test_bit_or_equals(0)) == 1335 | sizeof(large_result)); 1336 | static_assert( 1337 | sizeof(test_bit_and_equals(0)) == 1338 | sizeof(large_result)); 1339 | static_assert( 1340 | sizeof(test_bit_xor_equals(0)) == 1341 | sizeof(large_result)); 1342 | 1343 | static_assert( 1344 | sizeof(test_multiply_equals(0)) == 1345 | sizeof(large_result)); 1346 | static_assert( 1347 | sizeof(test_divide_equals(0)) == 1348 | sizeof(large_result)); 1349 | static_assert( 1350 | sizeof(test_mod_equals(0)) == 1351 | sizeof(large_result)); 1352 | static_assert( 1353 | sizeof(test_left_shift_equals(0)) == 1354 | sizeof(large_result)); 1355 | static_assert( 1356 | sizeof(test_right_shift_equals(0)) == 1357 | sizeof(large_result)); 1358 | static_assert( 1359 | sizeof(test_bit_or_equals(0)) == 1360 | sizeof(large_result)); 1361 | static_assert( 1362 | sizeof(test_bit_and_equals(0)) == 1363 | sizeof(large_result)); 1364 | static_assert( 1365 | sizeof(test_bit_xor_equals(0)) == 1366 | sizeof(large_result)); 1367 | 1368 | static_assert( 1369 | sizeof( 1370 | test_multiply_equals( 1371 | 0)) == sizeof(small_result)); 1372 | static_assert( 1373 | sizeof(test_divide_equals( 1374 | 0)) == sizeof(large_result)); 1375 | static_assert( 1376 | sizeof(test_mod_equals( 1377 | 0)) == sizeof(large_result)); 1378 | static_assert( 1379 | sizeof(test_left_shift_equals< 1380 | ST_compound_self_mult, ST_compound_self_mult>(0)) == 1381 | sizeof(large_result)); 1382 | static_assert( 1383 | sizeof(test_right_shift_equals< 1384 | ST_compound_self_mult, ST_compound_self_mult>(0)) == 1385 | sizeof(large_result)); 1386 | static_assert( 1387 | sizeof(test_bit_or_equals( 1388 | 0)) == sizeof(large_result)); 1389 | static_assert( 1390 | sizeof( 1391 | test_bit_and_equals( 1392 | 0)) == sizeof(large_result)); 1393 | static_assert( 1394 | sizeof( 1395 | test_bit_xor_equals( 1396 | 0)) == sizeof(large_result)); 1397 | 1398 | static_assert( 1399 | sizeof(test_multiply_equals(0)) == 1400 | sizeof(small_result)); 1401 | static_assert( 1402 | sizeof(test_divide_equals(0)) == 1403 | sizeof(large_result)); 1404 | static_assert( 1405 | sizeof(test_mod_equals(0)) == 1406 | sizeof(large_result)); 1407 | static_assert( 1408 | sizeof(test_left_shift_equals(0)) == 1409 | sizeof(large_result)); 1410 | static_assert( 1411 | sizeof(test_right_shift_equals(0)) == 1412 | sizeof(large_result)); 1413 | static_assert( 1414 | sizeof(test_bit_or_equals(0)) == 1415 | sizeof(large_result)); 1416 | static_assert( 1417 | sizeof(test_bit_and_equals(0)) == 1418 | sizeof(large_result)); 1419 | static_assert( 1420 | sizeof(test_bit_xor_equals(0)) == 1421 | sizeof(large_result)); 1422 | 1423 | static_assert( 1424 | sizeof(test_multiply_equals< 1425 | ST_compound_other_mult, ST_compound_other_mult>(0)) == 1426 | sizeof(large_result)); 1427 | static_assert( 1428 | sizeof( 1429 | test_divide_equals( 1430 | 0)) == sizeof(large_result)); 1431 | static_assert( 1432 | sizeof(test_mod_equals( 1433 | 0)) == sizeof(large_result)); 1434 | static_assert( 1435 | sizeof(test_left_shift_equals< 1436 | ST_compound_other_mult, ST_compound_other_mult>(0)) == 1437 | sizeof(large_result)); 1438 | static_assert( 1439 | sizeof(test_right_shift_equals< 1440 | ST_compound_other_mult, ST_compound_other_mult>(0)) == 1441 | sizeof(large_result)); 1442 | static_assert( 1443 | sizeof( 1444 | test_bit_or_equals( 1445 | 0)) == sizeof(large_result)); 1446 | static_assert( 1447 | sizeof( 1448 | test_bit_and_equals( 1449 | 0)) == sizeof(large_result)); 1450 | static_assert( 1451 | sizeof( 1452 | test_bit_xor_equals( 1453 | 0)) == sizeof(large_result)); 1454 | 1455 | static_assert( 1456 | sizeof(test_multiply_equals(0)) == 1457 | sizeof(large_result)); 1458 | static_assert( 1459 | sizeof(test_divide_equals(0)) == 1460 | sizeof(large_result)); 1461 | static_assert( 1462 | sizeof(test_mod_equals(0)) == 1463 | sizeof(large_result)); 1464 | static_assert( 1465 | sizeof(test_left_shift_equals(0)) == 1466 | sizeof(large_result)); 1467 | static_assert( 1468 | sizeof(test_right_shift_equals(0)) == 1469 | sizeof(large_result)); 1470 | static_assert( 1471 | sizeof(test_bit_or_equals(0)) == 1472 | sizeof(large_result)); 1473 | static_assert( 1474 | sizeof(test_bit_and_equals(0)) == 1475 | sizeof(large_result)); 1476 | static_assert( 1477 | sizeof(test_bit_xor_equals(0)) == 1478 | sizeof(large_result)); 1479 | 1480 | static_assert( 1481 | sizeof(test_multiply_equals< 1482 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1483 | sizeof(large_result)); 1484 | static_assert( 1485 | sizeof(test_divide_equals< 1486 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1487 | sizeof(small_result)); 1488 | static_assert( 1489 | sizeof( 1490 | test_mod_equals( 1491 | 0)) == sizeof(large_result)); 1492 | static_assert( 1493 | sizeof(test_left_shift_equals< 1494 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1495 | sizeof(large_result)); 1496 | static_assert( 1497 | sizeof(test_right_shift_equals< 1498 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1499 | sizeof(large_result)); 1500 | static_assert( 1501 | sizeof(test_bit_or_equals< 1502 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1503 | sizeof(large_result)); 1504 | static_assert( 1505 | sizeof(test_bit_and_equals< 1506 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1507 | sizeof(large_result)); 1508 | static_assert( 1509 | sizeof(test_bit_xor_equals< 1510 | ST_compound_self_divide, ST_compound_self_divide>(0)) == 1511 | sizeof(large_result)); 1512 | 1513 | static_assert( 1514 | sizeof(test_multiply_equals(0)) == 1515 | sizeof(large_result)); 1516 | static_assert( 1517 | sizeof(test_divide_equals(0)) == 1518 | sizeof(small_result)); 1519 | static_assert( 1520 | sizeof(test_mod_equals(0)) == 1521 | sizeof(large_result)); 1522 | static_assert( 1523 | sizeof(test_left_shift_equals(0)) == 1524 | sizeof(large_result)); 1525 | static_assert( 1526 | sizeof(test_right_shift_equals(0)) == 1527 | sizeof(large_result)); 1528 | static_assert( 1529 | sizeof(test_bit_or_equals(0)) == 1530 | sizeof(large_result)); 1531 | static_assert( 1532 | sizeof(test_bit_and_equals(0)) == 1533 | sizeof(large_result)); 1534 | static_assert( 1535 | sizeof(test_bit_xor_equals(0)) == 1536 | sizeof(large_result)); 1537 | 1538 | static_assert( 1539 | sizeof(test_multiply_equals< 1540 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1541 | sizeof(large_result)); 1542 | static_assert( 1543 | sizeof(test_divide_equals< 1544 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1545 | sizeof(large_result)); 1546 | static_assert( 1547 | sizeof( 1548 | test_mod_equals( 1549 | 0)) == sizeof(large_result)); 1550 | static_assert( 1551 | sizeof(test_left_shift_equals< 1552 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1553 | sizeof(large_result)); 1554 | static_assert( 1555 | sizeof(test_right_shift_equals< 1556 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1557 | sizeof(large_result)); 1558 | static_assert( 1559 | sizeof(test_bit_or_equals< 1560 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1561 | sizeof(large_result)); 1562 | static_assert( 1563 | sizeof(test_bit_and_equals< 1564 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1565 | sizeof(large_result)); 1566 | static_assert( 1567 | sizeof(test_bit_xor_equals< 1568 | ST_compound_other_divide, ST_compound_other_divide>(0)) == 1569 | sizeof(large_result)); 1570 | 1571 | static_assert( 1572 | sizeof(test_multiply_equals(0)) == 1573 | sizeof(large_result)); 1574 | static_assert( 1575 | sizeof(test_divide_equals(0)) == 1576 | sizeof(large_result)); 1577 | static_assert( 1578 | sizeof(test_mod_equals(0)) == 1579 | sizeof(large_result)); 1580 | static_assert( 1581 | sizeof(test_left_shift_equals(0)) == 1582 | sizeof(large_result)); 1583 | static_assert( 1584 | sizeof(test_right_shift_equals(0)) == 1585 | sizeof(large_result)); 1586 | static_assert( 1587 | sizeof(test_bit_or_equals(0)) == 1588 | sizeof(large_result)); 1589 | static_assert( 1590 | sizeof(test_bit_and_equals(0)) == 1591 | sizeof(large_result)); 1592 | static_assert( 1593 | sizeof(test_bit_xor_equals(0)) == 1594 | sizeof(large_result)); 1595 | 1596 | static_assert( 1597 | sizeof(test_multiply_equals(0)) == 1598 | sizeof(large_result)); 1599 | static_assert( 1600 | sizeof(test_divide_equals(0)) == 1601 | sizeof(large_result)); 1602 | static_assert( 1603 | sizeof(test_mod_equals(0)) == 1604 | sizeof(large_result)); 1605 | static_assert( 1606 | sizeof(test_left_shift_equals( 1607 | 0)) == sizeof(large_result)); 1608 | static_assert( 1609 | sizeof(test_right_shift_equals( 1610 | 0)) == sizeof(large_result)); 1611 | static_assert( 1612 | sizeof(test_bit_or_equals(0)) == 1613 | sizeof(large_result)); 1614 | static_assert( 1615 | sizeof(test_bit_and_equals(0)) == 1616 | sizeof(large_result)); 1617 | static_assert( 1618 | sizeof(test_bit_xor_equals(0)) == 1619 | sizeof(large_result)); 1620 | 1621 | static_assert( 1622 | sizeof(test_multiply_equals(0)) == 1623 | sizeof(large_result)); 1624 | static_assert( 1625 | sizeof(test_divide_equals(0)) == 1626 | sizeof(large_result)); 1627 | static_assert( 1628 | sizeof(test_mod_equals(0)) == 1629 | sizeof(large_result)); 1630 | static_assert( 1631 | sizeof(test_left_shift_equals(0)) == 1632 | sizeof(large_result)); 1633 | static_assert( 1634 | sizeof(test_right_shift_equals(0)) == 1635 | sizeof(large_result)); 1636 | static_assert( 1637 | sizeof(test_bit_or_equals(0)) == 1638 | sizeof(large_result)); 1639 | static_assert( 1640 | sizeof(test_bit_and_equals(0)) == 1641 | sizeof(large_result)); 1642 | static_assert( 1643 | sizeof(test_bit_xor_equals(0)) == 1644 | sizeof(large_result)); 1645 | 1646 | static_assert( 1647 | sizeof(test_multiply_equals( 1648 | 0)) == sizeof(large_result)); 1649 | static_assert( 1650 | sizeof(test_divide_equals( 1651 | 0)) == sizeof(large_result)); 1652 | static_assert( 1653 | sizeof(test_mod_equals( 1654 | 0)) == sizeof(small_result)); 1655 | static_assert( 1656 | sizeof( 1657 | test_left_shift_equals( 1658 | 0)) == sizeof(large_result)); 1659 | static_assert( 1660 | sizeof( 1661 | test_right_shift_equals( 1662 | 0)) == sizeof(large_result)); 1663 | static_assert( 1664 | sizeof(test_bit_or_equals( 1665 | 0)) == sizeof(large_result)); 1666 | static_assert( 1667 | sizeof(test_bit_and_equals( 1668 | 0)) == sizeof(large_result)); 1669 | static_assert( 1670 | sizeof(test_bit_xor_equals( 1671 | 0)) == sizeof(large_result)); 1672 | 1673 | static_assert( 1674 | sizeof(test_multiply_equals(0)) == 1675 | sizeof(large_result)); 1676 | static_assert( 1677 | sizeof(test_divide_equals(0)) == 1678 | sizeof(large_result)); 1679 | static_assert( 1680 | sizeof(test_mod_equals(0)) == 1681 | sizeof(small_result)); 1682 | static_assert( 1683 | sizeof(test_left_shift_equals(0)) == 1684 | sizeof(large_result)); 1685 | static_assert( 1686 | sizeof(test_right_shift_equals(0)) == 1687 | sizeof(large_result)); 1688 | static_assert( 1689 | sizeof(test_bit_or_equals(0)) == 1690 | sizeof(large_result)); 1691 | static_assert( 1692 | sizeof(test_bit_and_equals(0)) == 1693 | sizeof(large_result)); 1694 | static_assert( 1695 | sizeof(test_bit_xor_equals(0)) == 1696 | sizeof(large_result)); 1697 | 1698 | static_assert( 1699 | sizeof( 1700 | test_multiply_equals( 1701 | 0)) == sizeof(large_result)); 1702 | static_assert( 1703 | sizeof(test_divide_equals( 1704 | 0)) == sizeof(large_result)); 1705 | static_assert( 1706 | sizeof(test_mod_equals( 1707 | 0)) == sizeof(large_result)); 1708 | static_assert( 1709 | sizeof(test_left_shift_equals< 1710 | ST_compound_other_mod, ST_compound_other_mod>(0)) == 1711 | sizeof(large_result)); 1712 | static_assert( 1713 | sizeof(test_right_shift_equals< 1714 | ST_compound_other_mod, ST_compound_other_mod>(0)) == 1715 | sizeof(large_result)); 1716 | static_assert( 1717 | sizeof(test_bit_or_equals( 1718 | 0)) == sizeof(large_result)); 1719 | static_assert( 1720 | sizeof( 1721 | test_bit_and_equals( 1722 | 0)) == sizeof(large_result)); 1723 | static_assert( 1724 | sizeof( 1725 | test_bit_xor_equals( 1726 | 0)) == sizeof(large_result)); 1727 | 1728 | static_assert( 1729 | sizeof(test_bit_xor_equals( 1730 | 0)) == sizeof(small_result)); 1731 | static_assert( 1732 | sizeof(test_bit_xor_equals(0)) == 1733 | sizeof(large_result)); 1734 | 1735 | static_assert( 1736 | sizeof( 1737 | test_bit_xor_equals( 1738 | 0)) == sizeof(large_result)); 1739 | static_assert( 1740 | sizeof(test_bit_xor_equals(0)) == 1741 | sizeof(small_result)); 1742 | 1743 | static_assert( 1744 | sizeof(test_bit_and_equals( 1745 | 0)) == sizeof(small_result)); 1746 | static_assert( 1747 | sizeof(test_bit_and_equals(0)) == 1748 | sizeof(large_result)); 1749 | 1750 | static_assert( 1751 | sizeof( 1752 | test_bit_and_equals( 1753 | 0)) == sizeof(large_result)); 1754 | static_assert( 1755 | sizeof(test_bit_and_equals(0)) == 1756 | sizeof(small_result)); 1757 | 1758 | static_assert( 1759 | sizeof(test_bit_or_equals( 1760 | 0)) == sizeof(small_result)); 1761 | static_assert( 1762 | sizeof(test_bit_or_equals(0)) == 1763 | sizeof(large_result)); 1764 | 1765 | static_assert( 1766 | sizeof(test_bit_or_equals( 1767 | 0)) == sizeof(large_result)); 1768 | static_assert( 1769 | sizeof(test_bit_or_equals(0)) == 1770 | sizeof(small_result)); 1771 | 1772 | static_assert( 1773 | sizeof(test_left_shift_equals< 1774 | ST_compound_left_shift, ST_compound_left_shift>(0)) == 1775 | sizeof(large_result)); 1776 | static_assert( 1777 | sizeof(test_left_shift_equals(0)) == 1778 | sizeof(small_result)); 1779 | 1780 | static_assert( 1781 | sizeof(test_right_shift_equals< 1782 | ST_compound_right_shift, ST_compound_right_shift>(0)) == 1783 | sizeof(large_result)); 1784 | static_assert( 1785 | sizeof(test_right_shift_equals(0)) == 1786 | sizeof(small_result)); 1787 | 1788 | ST_compound_add st1(42); 1789 | st1+= 9; 1790 | assert(st1.underlying_value() == 51); 1791 | ST_compound_sub st2(42); 1792 | st2-= 3; 1793 | assert(st2.underlying_value() == 39); 1794 | ST_compound_self_mult st3(6); 1795 | ST_compound_self_mult st4(7); 1796 | st3*= st4; 1797 | assert(st3.underlying_value() == 42); 1798 | 1799 | ST_compound_other_mult st5(9); 1800 | st5*= 6; 1801 | assert(st5.underlying_value() == 54); 1802 | } 1803 | 1804 | void test_adding_two_strong_typedefs() { 1805 | std::cout << __FUNCTION__ << std::endl; 1806 | 1807 | using ST1= jss::strong_typedef; 1808 | using ST2= jss::strong_typedef< 1809 | struct tag2, int, jss::strong_typedef_properties::mixed_addable>; 1810 | 1811 | constexpr ST1 st1(23); 1812 | constexpr ST2 st2(46); 1813 | 1814 | constexpr ST2 st3= st2 + st1; 1815 | constexpr ST2 st4= st1 + st2; 1816 | 1817 | static_assert(st3.underlying_value() == 69); 1818 | static_assert(st4.underlying_value() == 69); 1819 | 1820 | using STS1= jss::strong_typedef; 1821 | using STS2= jss::strong_typedef< 1822 | struct tag2, std::string, 1823 | jss::strong_typedef_properties::mixed_addable>; 1824 | 1825 | STS1 sts1("hello"); 1826 | STS2 sts2("world"); 1827 | 1828 | STS2 sts3= sts2 + sts1; 1829 | STS2 sts4= sts1 + sts2; 1830 | 1831 | assert(sts3.underlying_value() == "worldhello"); 1832 | assert(sts4.underlying_value() == "helloworld"); 1833 | } 1834 | int main() { 1835 | test_strong_typedef_is_not_original(); 1836 | test_strong_typedef_explicitly_convertible_from_source(); 1837 | test_strong_typedef_not_implicitly_convertible_from_source(); 1838 | test_strong_typedef_explicitly_convertible_to_source(); 1839 | test_strong_typedef_not_implicitly_convertible_to_source(); 1840 | test_strong_typedef_is_copyable_and_movable(); 1841 | test_by_default_strong_typedef_is_not_equality_comparable(); 1842 | test_can_get_underlying_value_and_type(); 1843 | test_strong_typedef_is_equality_comparable_if_tagged_as_such(); 1844 | test_by_default_strong_typedef_is_not_incrementable(); 1845 | test_strong_typedef_is_incrementable_if_tagged_as_such(); 1846 | test_by_default_strong_typedef_is_not_decrementable(); 1847 | test_strong_typedef_is_decrementable_if_tagged_as_such(); 1848 | test_by_default_strong_typedef_is_not_addable(); 1849 | test_strong_typedef_is_addable_if_tagged_as_such(); 1850 | test_by_default_strong_typedef_is_not_subtractable(); 1851 | test_strong_typedef_is_subtractable_if_tagged_as_such(); 1852 | test_by_default_strong_typedef_is_not_ordered(); 1853 | test_strong_typedef_is_ordered_if_tagged_as_such(); 1854 | test_strong_typedef_is_mixed_ordered_if_tagged_as_such(); 1855 | test_by_default_strong_typedef_is_not_hashable(); 1856 | test_strong_typedef_is_hashable_if_tagged_as_such(); 1857 | test_by_default_strong_typedef_is_not_streamable(); 1858 | test_strong_typedef_is_streamable_if_tagged_as_such(); 1859 | test_properties_can_be_combined(); 1860 | test_strong_typedef_is_default_constructible(); 1861 | test_can_support_difference_with_other_type(); 1862 | test_self_multiplication(); 1863 | test_mixed_multiplication(); 1864 | test_self_division(); 1865 | test_mixed_division(); 1866 | test_self_modulus(); 1867 | test_mixed_modulus(); 1868 | test_ratio(); 1869 | test_constexpr_comparison(); 1870 | test_constexpr_addition(); 1871 | test_constexpr_subtraction(); 1872 | test_bitwise_or(); 1873 | test_bitwise_and(); 1874 | test_bitwise_xor(); 1875 | test_bitwise_not(); 1876 | test_bitwise_left_shift(); 1877 | test_bitwise_right_shift(); 1878 | test_compound_assignment(); 1879 | test_adding_two_strong_typedefs(); 1880 | } 1881 | --------------------------------------------------------------------------------