├── .travis.yml ├── CMakeLists.txt ├── LICENSE ├── README.md ├── appveyor.yml ├── biicode.conf ├── doc ├── Makefile ├── conf.py ├── genreadme ├── index.rst ├── make.bat ├── requirements.txt └── src │ ├── acknowledgments.md │ ├── builder.md │ ├── check.md │ ├── design.md │ ├── index.md │ ├── license.md │ ├── requirements.md │ ├── requires.md │ ├── tag.md │ ├── traits.rst │ └── zlang.md ├── mkdocs.yml ├── test ├── builder.cpp ├── fold.cpp ├── integral_constant.cpp ├── matches.cpp ├── requires.cpp ├── set.cpp ├── tag.cpp ├── test.h ├── trait_check.cpp └── traits.cpp ├── tick.pc.in └── tick ├── builder.h ├── detail ├── fold.h ├── matches.h ├── pp.h ├── set.h └── using.h ├── integral_constant.h ├── placeholders.h ├── requires.h ├── tag.h ├── trait_check.h ├── traits.h └── traits ├── bare.h ├── is_allocator.h ├── is_associative_container.h ├── is_bidirectional_iterator.h ├── is_compare.h ├── is_container.h ├── is_copy_assignable.h ├── is_copy_constructible.h ├── is_copy_insertable.h ├── is_default_constructible.h ├── is_destructible.h ├── is_emplace_constructible.h ├── is_equality_comparable.h ├── is_erasable.h ├── is_forward_iterator.h ├── is_input_iterator.h ├── is_iterator.h ├── is_less_than_comparable.h ├── is_move_assignable.h ├── is_move_constructible.h ├── is_move_insertable.h ├── is_mutable_bidirectional_iterator.h ├── is_mutable_forward_iterator.h ├── is_mutable_random_access_iterator.h ├── is_nullable_pointer.h ├── is_output_iterator.h ├── is_pod.h ├── is_predicate.h ├── is_random_access_iterator.h ├── is_range.h ├── is_reversible_container.h ├── is_sequence_container.h ├── is_standard_layout.h ├── is_swappable.h ├── is_totally_ordered.h ├── is_trivial.h ├── is_trivially_copyable.h ├── is_value_swappable.h └── is_weakly_ordered.h /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project (Tick) 3 | 4 | # The version number. 5 | set (Tick_VERSION_MAJOR 1) 6 | set (Tick_VERSION_MINOR 2) 7 | 8 | include(CheckCXXCompilerFlag) 9 | enable_language(CXX) 10 | 11 | if(CMAKE_HOST_APPLE) 12 | check_cxx_compiler_flag("-stdlib=libc++" COMPILER_HAS_CXX_FLAG_libcxx) 13 | if(COMPILER_HAS_CXX_FLAG_libcxx) 14 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 15 | endif() 16 | endif() 17 | 18 | set(ENABLE_CXXFLAGS_TO_CHECK 19 | -std=gnu++1y 20 | -std=c++1y 21 | -std=gnu++11 22 | -std=c++11 23 | -std=gnu++0x 24 | -std=c++0x) 25 | 26 | foreach(flag ${ENABLE_CXXFLAGS_TO_CHECK}) 27 | string(REPLACE "-std=" "_" flag_var ${flag}) 28 | string(REPLACE "+" "x" flag_var ${flag_var}) 29 | check_cxx_compiler_flag("${flag}" COMPILER_HAS_CXX_FLAG${flag_var}) 30 | if(COMPILER_HAS_CXX_FLAG${flag_var}) 31 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}") 32 | break() 33 | endif() 34 | endforeach() 35 | 36 | 37 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) 38 | 39 | macro(add_test_executable TEST_NAME_) 40 | set(TEST_NAME "${TEST_NAME_}") 41 | add_executable (${TEST_NAME} EXCLUDE_FROM_ALL test/${TEST_NAME}.cpp ${ARGN}) 42 | if(WIN32) 43 | add_test(NAME ${TEST_NAME} WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} COMMAND ${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX}) 44 | else() 45 | add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) 46 | endif() 47 | add_dependencies(check ${TEST_NAME}) 48 | set_tests_properties(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION "FAILED") 49 | endmacro(add_test_executable) 50 | 51 | include(CTest) 52 | 53 | install (DIRECTORY tick DESTINATION include) 54 | 55 | configure_file(tick.pc.in tick.pc) 56 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tick.pc DESTINATION lib/pkgconfig) 57 | include_directories(.) 58 | 59 | add_test_executable(builder) 60 | add_test_executable(fold) 61 | add_test_executable(integral_constant) 62 | add_test_executable(matches) 63 | add_test_executable(requires) 64 | add_test_executable(set) 65 | add_test_executable(tag) 66 | add_test_executable(trait_check) 67 | add_test_executable(traits) 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | 2 | os: Visual Studio 2015 3 | 4 | environment: 5 | matrix: 6 | # - GENERATOR: "Visual Studio 14 2015 Win64" 7 | # CONFIG: Debug 8 | 9 | # - GENERATOR: "Visual Studio 14 2015 Win64" 10 | # CONFIG: Release 11 | 12 | - GENERATOR: "Visual Studio 14 2015" 13 | CONFIG: Debug 14 | 15 | - GENERATOR: "Visual Studio 14 2015" 16 | CONFIG: Release 17 | 18 | matrix: 19 | fast_finish: true 20 | 21 | build_script: 22 | - cmd: set PATH=C:\Program Files (x86)\CMake\bin;%PATH% 23 | - cmd: set PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% 24 | - cmd: call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Tools\vsvars32.bat" 25 | - cmd: set CTEST_OUTPUT_ON_FAILURE=1 26 | - cmd: cmake --version 27 | - cmd: mkdir build 28 | - cmd: cd build 29 | - cmd: cmake .. -G"%GENERATOR%" 30 | - cmd: cmake --build . --config %CONFIG% --target check 31 | -------------------------------------------------------------------------------- /biicode.conf: -------------------------------------------------------------------------------- 1 | # Biicode configuration file 2 | 3 | [requirements] 4 | # Blocks and versions this block depends on e.g. 5 | # user/depblock1: 3 6 | # user2/depblock2(track) @tag 7 | 8 | [parent] 9 | pfultz2/Tick: 0 10 | [paths] 11 | # Local directories to look for headers (within block) 12 | / 13 | # include 14 | 15 | [dependencies] 16 | # Manual adjust file implicit dependencies, add (+), remove (-), or overwrite (=) 17 | # hello.h + hello_imp.cpp hello_imp2.cpp 18 | # *.h + *.cpp 19 | 20 | [mains] 21 | # Manual adjust of files that define an executable 22 | # !main.cpp # Do not build executable from this file 23 | # main2.cpp # Build it (it doesnt have a main() function, but maybe it includes it) 24 | !test/test.h 25 | test/*.cpp 26 | [tests] 27 | # Manual adjust of files that define a CTest test 28 | # test/* pattern to evaluate this test/ folder sources like tests 29 | test/*.cpp 30 | [hooks] 31 | # These are defined equal to [dependencies],files names matching bii*stage*hook.py 32 | # will be launched as python scripts at stage = {post_process, clean} 33 | # CMakeLists.txt + bii/my_post_process1_hook.py bii_clean_hook.py 34 | 35 | [includes] 36 | # Mapping of include patterns to external blocks 37 | # hello*.h: user3/depblock # includes will be processed as user3/depblock/hello*.h 38 | 39 | [data] 40 | # Manually define data files dependencies, that will be copied to bin for execution 41 | # By default they are copied to bin/user/block/... which should be taken into account 42 | # when loading from disk such data 43 | # image.cpp + image.jpg # code should write open("user/block/image.jpg") 44 | 45 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help 18 | help: 19 | @echo "Please use \`make ' where is one of" 20 | @echo " html to make standalone HTML files" 21 | @echo " dirhtml to make HTML files named index.html in directories" 22 | @echo " singlehtml to make a single large HTML file" 23 | @echo " pickle to make pickle files" 24 | @echo " json to make JSON files" 25 | @echo " htmlhelp to make HTML files and a HTML help project" 26 | @echo " qthelp to make HTML files and a qthelp project" 27 | @echo " applehelp to make an Apple Help Book" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " epub3 to make an epub3" 31 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 32 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 33 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 34 | @echo " text to make text files" 35 | @echo " man to make manual pages" 36 | @echo " texinfo to make Texinfo files" 37 | @echo " info to make Texinfo files and run them through makeinfo" 38 | @echo " gettext to make PO message catalogs" 39 | @echo " changes to make an overview of all changed/added/deprecated items" 40 | @echo " xml to make Docutils-native XML files" 41 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 42 | @echo " linkcheck to check all external links for integrity" 43 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 44 | @echo " coverage to run coverage check of the documentation (if enabled)" 45 | @echo " dummy to check syntax errors of document sources" 46 | 47 | .PHONY: clean 48 | clean: 49 | rm -rf $(BUILDDIR)/* 50 | 51 | .PHONY: html 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | .PHONY: dirhtml 58 | dirhtml: 59 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 60 | @echo 61 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 62 | 63 | .PHONY: singlehtml 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | .PHONY: pickle 70 | pickle: 71 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 72 | @echo 73 | @echo "Build finished; now you can process the pickle files." 74 | 75 | .PHONY: json 76 | json: 77 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 78 | @echo 79 | @echo "Build finished; now you can process the JSON files." 80 | 81 | .PHONY: htmlhelp 82 | htmlhelp: 83 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 84 | @echo 85 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 86 | ".hhp project file in $(BUILDDIR)/htmlhelp." 87 | 88 | .PHONY: qthelp 89 | qthelp: 90 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 91 | @echo 92 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 93 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 94 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Tick.qhcp" 95 | @echo "To view the help file:" 96 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Tick.qhc" 97 | 98 | .PHONY: applehelp 99 | applehelp: 100 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 101 | @echo 102 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 103 | @echo "N.B. You won't be able to view it unless you put it in" \ 104 | "~/Library/Documentation/Help or install it in your application" \ 105 | "bundle." 106 | 107 | .PHONY: devhelp 108 | devhelp: 109 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 110 | @echo 111 | @echo "Build finished." 112 | @echo "To view the help file:" 113 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Tick" 114 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Tick" 115 | @echo "# devhelp" 116 | 117 | .PHONY: epub 118 | epub: 119 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 120 | @echo 121 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 122 | 123 | .PHONY: epub3 124 | epub3: 125 | $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3 126 | @echo 127 | @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3." 128 | 129 | .PHONY: latex 130 | latex: 131 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 132 | @echo 133 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 134 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 135 | "(use \`make latexpdf' here to do that automatically)." 136 | 137 | .PHONY: latexpdf 138 | latexpdf: 139 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 140 | @echo "Running LaTeX files through pdflatex..." 141 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 142 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 143 | 144 | .PHONY: latexpdfja 145 | latexpdfja: 146 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 147 | @echo "Running LaTeX files through platex and dvipdfmx..." 148 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 149 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 150 | 151 | .PHONY: text 152 | text: 153 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 154 | @echo 155 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 156 | 157 | .PHONY: man 158 | man: 159 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 160 | @echo 161 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 162 | 163 | .PHONY: texinfo 164 | texinfo: 165 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 166 | @echo 167 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 168 | @echo "Run \`make' in that directory to run these through makeinfo" \ 169 | "(use \`make info' here to do that automatically)." 170 | 171 | .PHONY: info 172 | info: 173 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 174 | @echo "Running Texinfo files through makeinfo..." 175 | make -C $(BUILDDIR)/texinfo info 176 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 177 | 178 | .PHONY: gettext 179 | gettext: 180 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 181 | @echo 182 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 183 | 184 | .PHONY: changes 185 | changes: 186 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 187 | @echo 188 | @echo "The overview file is in $(BUILDDIR)/changes." 189 | 190 | .PHONY: linkcheck 191 | linkcheck: 192 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 193 | @echo 194 | @echo "Link check complete; look for any errors in the above output " \ 195 | "or in $(BUILDDIR)/linkcheck/output.txt." 196 | 197 | .PHONY: doctest 198 | doctest: 199 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 200 | @echo "Testing of doctests in the sources finished, look at the " \ 201 | "results in $(BUILDDIR)/doctest/output.txt." 202 | 203 | .PHONY: coverage 204 | coverage: 205 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 206 | @echo "Testing of coverage in the sources finished, look at the " \ 207 | "results in $(BUILDDIR)/coverage/python.txt." 208 | 209 | .PHONY: xml 210 | xml: 211 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 212 | @echo 213 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 214 | 215 | .PHONY: pseudoxml 216 | pseudoxml: 217 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 218 | @echo 219 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 220 | 221 | .PHONY: dummy 222 | dummy: 223 | $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy 224 | @echo 225 | @echo "Build finished. Dummy builder generates no files." 226 | -------------------------------------------------------------------------------- /doc/genreadme: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat src/index.md src/builder.md src/requires.md src/check.md src/requirements.md src/zlang.md src/acknowledgments.md -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | 2 | 3 | Tick 4 | ==== 5 | 6 | **Paul Fultz II** 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | src/index 12 | src/requirements 13 | src/builder 14 | src/requires 15 | src/tag 16 | src/traits 17 | src/design 18 | src/zlang 19 | src/acknowledgments 20 | src/license 21 | 22 | 23 | 24 | Search 25 | ====== 26 | 27 | * :ref:`search` 28 | 29 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. epub3 to make an epub3 31 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 32 | echo. text to make text files 33 | echo. man to make manual pages 34 | echo. texinfo to make Texinfo files 35 | echo. gettext to make PO message catalogs 36 | echo. changes to make an overview over all changed/added/deprecated items 37 | echo. xml to make Docutils-native XML files 38 | echo. pseudoxml to make pseudoxml-XML files for display purposes 39 | echo. linkcheck to check all external links for integrity 40 | echo. doctest to run all doctests embedded in the documentation if enabled 41 | echo. coverage to run coverage check of the documentation if enabled 42 | echo. dummy to check syntax errors of document sources 43 | goto end 44 | ) 45 | 46 | if "%1" == "clean" ( 47 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 48 | del /q /s %BUILDDIR%\* 49 | goto end 50 | ) 51 | 52 | 53 | REM Check if sphinx-build is available and fallback to Python version if any 54 | %SPHINXBUILD% 1>NUL 2>NUL 55 | if errorlevel 9009 goto sphinx_python 56 | goto sphinx_ok 57 | 58 | :sphinx_python 59 | 60 | set SPHINXBUILD=python -m sphinx.__init__ 61 | %SPHINXBUILD% 2> nul 62 | if errorlevel 9009 ( 63 | echo. 64 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 65 | echo.installed, then set the SPHINXBUILD environment variable to point 66 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 67 | echo.may add the Sphinx directory to PATH. 68 | echo. 69 | echo.If you don't have Sphinx installed, grab it from 70 | echo.http://sphinx-doc.org/ 71 | exit /b 1 72 | ) 73 | 74 | :sphinx_ok 75 | 76 | 77 | if "%1" == "html" ( 78 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 79 | if errorlevel 1 exit /b 1 80 | echo. 81 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 82 | goto end 83 | ) 84 | 85 | if "%1" == "dirhtml" ( 86 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 87 | if errorlevel 1 exit /b 1 88 | echo. 89 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 90 | goto end 91 | ) 92 | 93 | if "%1" == "singlehtml" ( 94 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 95 | if errorlevel 1 exit /b 1 96 | echo. 97 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 98 | goto end 99 | ) 100 | 101 | if "%1" == "pickle" ( 102 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 103 | if errorlevel 1 exit /b 1 104 | echo. 105 | echo.Build finished; now you can process the pickle files. 106 | goto end 107 | ) 108 | 109 | if "%1" == "json" ( 110 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 111 | if errorlevel 1 exit /b 1 112 | echo. 113 | echo.Build finished; now you can process the JSON files. 114 | goto end 115 | ) 116 | 117 | if "%1" == "htmlhelp" ( 118 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 119 | if errorlevel 1 exit /b 1 120 | echo. 121 | echo.Build finished; now you can run HTML Help Workshop with the ^ 122 | .hhp project file in %BUILDDIR%/htmlhelp. 123 | goto end 124 | ) 125 | 126 | if "%1" == "qthelp" ( 127 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 128 | if errorlevel 1 exit /b 1 129 | echo. 130 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 131 | .qhcp project file in %BUILDDIR%/qthelp, like this: 132 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Tick.qhcp 133 | echo.To view the help file: 134 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Tick.ghc 135 | goto end 136 | ) 137 | 138 | if "%1" == "devhelp" ( 139 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 140 | if errorlevel 1 exit /b 1 141 | echo. 142 | echo.Build finished. 143 | goto end 144 | ) 145 | 146 | if "%1" == "epub" ( 147 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 148 | if errorlevel 1 exit /b 1 149 | echo. 150 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 151 | goto end 152 | ) 153 | 154 | if "%1" == "epub3" ( 155 | %SPHINXBUILD% -b epub3 %ALLSPHINXOPTS% %BUILDDIR%/epub3 156 | if errorlevel 1 exit /b 1 157 | echo. 158 | echo.Build finished. The epub3 file is in %BUILDDIR%/epub3. 159 | goto end 160 | ) 161 | 162 | if "%1" == "latex" ( 163 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 164 | if errorlevel 1 exit /b 1 165 | echo. 166 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdf" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "latexpdfja" ( 181 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 182 | cd %BUILDDIR%/latex 183 | make all-pdf-ja 184 | cd %~dp0 185 | echo. 186 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 187 | goto end 188 | ) 189 | 190 | if "%1" == "text" ( 191 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 192 | if errorlevel 1 exit /b 1 193 | echo. 194 | echo.Build finished. The text files are in %BUILDDIR%/text. 195 | goto end 196 | ) 197 | 198 | if "%1" == "man" ( 199 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 200 | if errorlevel 1 exit /b 1 201 | echo. 202 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 203 | goto end 204 | ) 205 | 206 | if "%1" == "texinfo" ( 207 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 208 | if errorlevel 1 exit /b 1 209 | echo. 210 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 211 | goto end 212 | ) 213 | 214 | if "%1" == "gettext" ( 215 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 216 | if errorlevel 1 exit /b 1 217 | echo. 218 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 219 | goto end 220 | ) 221 | 222 | if "%1" == "changes" ( 223 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 224 | if errorlevel 1 exit /b 1 225 | echo. 226 | echo.The overview file is in %BUILDDIR%/changes. 227 | goto end 228 | ) 229 | 230 | if "%1" == "linkcheck" ( 231 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 232 | if errorlevel 1 exit /b 1 233 | echo. 234 | echo.Link check complete; look for any errors in the above output ^ 235 | or in %BUILDDIR%/linkcheck/output.txt. 236 | goto end 237 | ) 238 | 239 | if "%1" == "doctest" ( 240 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 241 | if errorlevel 1 exit /b 1 242 | echo. 243 | echo.Testing of doctests in the sources finished, look at the ^ 244 | results in %BUILDDIR%/doctest/output.txt. 245 | goto end 246 | ) 247 | 248 | if "%1" == "coverage" ( 249 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 250 | if errorlevel 1 exit /b 1 251 | echo. 252 | echo.Testing of coverage in the sources finished, look at the ^ 253 | results in %BUILDDIR%/coverage/python.txt. 254 | goto end 255 | ) 256 | 257 | if "%1" == "xml" ( 258 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 259 | if errorlevel 1 exit /b 1 260 | echo. 261 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 262 | goto end 263 | ) 264 | 265 | if "%1" == "pseudoxml" ( 266 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 267 | if errorlevel 1 exit /b 1 268 | echo. 269 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 270 | goto end 271 | ) 272 | 273 | if "%1" == "dummy" ( 274 | %SPHINXBUILD% -b dummy %ALLSPHINXOPTS% %BUILDDIR%/dummy 275 | if errorlevel 1 exit /b 1 276 | echo. 277 | echo.Build finished. Dummy builder generates no files. 278 | goto end 279 | ) 280 | 281 | :end 282 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/pfultz2/recommonmark@develop 2 | git+https://github.com/pfultz2/sphinx@develop 3 | sphinx-boost>0.0.2 4 | tabulate 5 | -------------------------------------------------------------------------------- /doc/src/acknowledgments.md: -------------------------------------------------------------------------------- 1 | Acknowledgments 2 | =============== 3 | 4 | * Eric Niebler for the idea of using a `requires` member function to check concept traits.[http://ericniebler.com/2013/11/23/concept-checking-in-c11/] 5 | * Jamboree for the idea of using a template class to place expressions.[https://github.com/ericniebler/range-v3/issues/29#issuecomment-51016277] 6 | 7 | -------------------------------------------------------------------------------- /doc/src/builder.md: -------------------------------------------------------------------------------- 1 | Building traits 2 | =============== 3 | 4 | TICK_TRAIT 5 | ---------- 6 | 7 | This macro will build a boolean type trait for you. Each trait has a `require` member function of the form: 8 | ```cpp 9 | TICK_TRAIT(my_trait) 10 | { 11 | template 12 | auto require(T&& x) -> valid< 13 | ... 14 | >; 15 | }; 16 | ``` 17 | 18 | This will essentially build a class that inherits from `integral_constant`, so the above is equivalent to this: 19 | 20 | ```cpp 21 | template 22 | struct my_trait 23 | : integral_constant 24 | {}; 25 | ``` 26 | The parameters to the trait are based on the parameters passed to the `require` function. 27 | 28 | The trait will be either true or false if the expressions given are valid. Each expression in `valid` needs a `decltype` around it. If one of the expressions is not valid, the the trait will return false. For example, 29 | ```cpp 30 | TICK_TRAIT(my_trait) 31 | { 32 | template 33 | auto require(T&& x) -> valid< 34 | decltype(x++) 35 | >; 36 | }; 37 | ``` 38 | The trait above will check that `x++` is a valid expression. 39 | 40 | Refinements 41 | ----------- 42 | 43 | Refinements can be expressed after the name. Each refinement is a [placeholder expression](http://www.boost.org/doc/libs/1_55_0/libs/mpl/doc/refmanual/placeholder-expression.html), where each placeholder(ie `_1`, `_2`, etc) are replaced by their corresponding type passed into the trait. In the case of traits that accept a single parameter the unnamed placeholder(`_`) can be used, for example: 44 | ```cpp 45 | TICK_TRAIT(is_incrementable, std::is_default_constructible<_>) 46 | { 47 | template 48 | auto require(T&& x) -> valid< 49 | decltype(x++), 50 | decltype(++x) 51 | >; 52 | }; 53 | ``` 54 | This trait will be true when `x++` and `++x` are valid expressions and `x` is default constructible. 55 | 56 | When a trait has multiple parameters, its best to use named placeholders. For example: 57 | ```cpp 58 | TICK_TRAIT(is_equality_comparable, 59 | std::is_default_constructible<_1>, 60 | std::is_default_constructible<_2>) 61 | { 62 | template 63 | auto require(T&& x, U&& y) -> valid< 64 | decltype(x == y), 65 | decltype(x != y) 66 | >; 67 | }; 68 | ``` 69 | This trait will be true when `x == y` and `x != y` are valid expressions and both `x` and `y` are default constructible. 70 | 71 | In addition `quote` can be used to pass all the args from the trait to the refinement: 72 | 73 | ```cpp 74 | TICK_TRAIT(is_comparable, 75 | quote) 76 | { 77 | template 78 | auto require(T&& x, U&& y) -> valid< 79 | decltype(x < y), 80 | decltype(x <= y), 81 | decltype(x >= y), 82 | decltype(x > y) 83 | >; 84 | }; 85 | ``` 86 | 87 | Query operations 88 | ================ 89 | 90 | These can be used to query more information about the types then just valid expressions. 91 | 92 | When a type is matched in query operation, it can either be convertible to the type given, or the evaluated [placeholder expression](http://www.boost.org/doc/libs/1_55_0/libs/mpl/doc/refmanual/placeholder-expression.html) must be true. Placeholder expressions can be given so the type can be matched against other traits. 93 | 94 | 95 | returns 96 | ------- 97 | 98 | The `returns` query can check if the result of the expressions matches the type. For example, 99 | ```cpp 100 | TICK_TRAIT(is_incrementable) 101 | { 102 | template 103 | auto require(T&& x) -> valid< 104 | decltype(returns(x++)) 105 | >; 106 | }; 107 | ``` 108 | This trait will be true if the expressions `x++` is valid and is convertible to `int`. 109 | 110 | Here's an example using placeholder expressions as well: 111 | ```cpp 112 | TICK_TRAIT(is_incrementable) 113 | { 114 | template 115 | auto require(T&& x) -> valid< 116 | decltype(returns>(x++)) 117 | >; 118 | }; 119 | ``` 120 | This trait will be true if the expressions `x++` is valid and returns a type that `is_integral`. 121 | 122 | Note: The `TICK_RETURNS` macro can be used instead to improve compatability with older compilers(such as gcc 4.6): 123 | ```cpp 124 | TICK_TRAIT(is_incrementable) 125 | { 126 | template 127 | auto require(T&& x) -> valid< 128 | TICK_RETURNS(x++, int) 129 | >; 130 | }; 131 | ``` 132 | 133 | Also, `returns` is prohibited. 134 | 135 | ```cpp 136 | TICK_TRAIT(is_incrementable) 137 | { 138 | template 139 | auto require(T&& x) -> valid< 140 | decltype(returns(x++)) // Compiler error 141 | >; 142 | }; 143 | ``` 144 | 145 | Instead, use either `decltype` directly without `returns`, or if there is a possibility of `void` from a computed type, use `TICK_RETURNS` or `has_type` instead. 146 | 147 | has_type 148 | -------- 149 | 150 | The `has_type` query can check if a type exist and if the type matches. For example: 151 | ```cpp 152 | TICK_TRAIT(has_nested_type) 153 | { 154 | template 155 | auto require(const T& x) -> valid< 156 | has_type 157 | >; 158 | }; 159 | ``` 160 | This trait will be true if `T` has a nested type called `type`. 161 | 162 | Now `has_type` used as above is not quite as useful since the above example, can also be simply written without `has_type` like this: 163 | ```cpp 164 | TICK_TRAIT(has_nested_type) 165 | { 166 | template 167 | auto require(const T& x) -> valid< 168 | typename T::type 169 | >; 170 | }; 171 | ``` 172 | So, an optional second parameter can be provided to check if the type matches. Here's an example: 173 | ```cpp 174 | TICK_TRAIT(has_nested_int_type) 175 | { 176 | template 177 | auto require(const T& x) -> valid< 178 | has_type> 179 | >; 180 | }; 181 | ``` 182 | This trait will be true if `T` has a nested type called `type` which is an integral type. 183 | 184 | has_template 185 | ------------ 186 | 187 | The `has_template` query can check if a template exist. For example: 188 | ```cpp 189 | TICK_TRAIT(has_nested_result) 190 | { 191 | template 192 | auto require(const T& x) -> valid< 193 | has_template 194 | >; 195 | }; 196 | ``` 197 | This trait will be true if `T` has a nested template called `result`. 198 | 199 | is_true 200 | ------- 201 | 202 | The `is_true` query can check if a trait is true. Using [refinements](refinements) is the preferred way of checking for additional traits, but this can be useful if the evaluation of some trait can't be used lazily with [placeholder expression](http://www.boost.org/doc/libs/1_55_0/libs/mpl/doc/refmanual/placeholder-expression.html). So `is_true` can be used instead, for example: 203 | ```cpp 204 | TICK_TRAIT(is_2d_array) 205 | { 206 | template 207 | auto require(const T& x) -> valid< 208 | is_true::type, std::integral_constant> > 209 | >; 210 | }; 211 | ``` 212 | 213 | is_false 214 | -------- 215 | 216 | The `is_false` query can check if a trait is false. Using [refinements](refinements) is the preferred way of checking for additional traits, but this can be useful if the evaluation of some trait can't be used lazily with [placeholder expression](http://www.boost.org/doc/libs/1_55_0/libs/mpl/doc/refmanual/placeholder-expression.html). So `is_false` can be used instead, for example: 217 | ```cpp 218 | TICK_TRAIT(is_multi_array) 219 | { 220 | template 221 | auto require(const T& x) -> valid< 222 | is_false::type, std::integral_constant> > 223 | >; 224 | }; 225 | ``` 226 | 227 | as_const 228 | -------- 229 | 230 | The `as_const` function helps ensure that lvalues are `const`. 231 | 232 | ```cpp 233 | TICK_TRAIT(is_copy_assignable) 234 | { 235 | template 236 | auto require(T&& x) -> valid< 237 | decltype(x = as_const(x)) 238 | >; 239 | }; 240 | ``` 241 | 242 | as_mutable 243 | ---------- 244 | 245 | The `as_mutable` function helps ensure that lvalues are treated as `mutable` or non-const. 246 | 247 | ```cpp 248 | TICK_TRAIT(is_destructible) 249 | { 250 | template 251 | auto require(const T& x) -> valid< 252 | decltype(as_mutable(x).~T()) 253 | >; 254 | }; 255 | ``` 256 | 257 | Build traits without macros 258 | =========================== 259 | 260 | The traits can be built without using the `TICK_TRAIT` macros. However, it may introduce problems with portability. So if only one platform is needed to be supported, then here's how to build them. First, build a class for the `require` functions and inherit from `tick::ops` to bring in all the query operations: 261 | ```cpp 262 | struct is_incrementable_r : tick::ops 263 | { 264 | template 265 | auto require(T&& x) -> valid< 266 | decltype(x++), 267 | decltype(++x) 268 | >; 269 | }; 270 | ``` 271 | Next, turn it into a trait using `tick::models`: 272 | ```cpp 273 | template 274 | struct is_incrementable 275 | : tick::models 276 | {}; 277 | ``` 278 | 279 | refines 280 | ------- 281 | 282 | Refinements can be used by using the `refines` class: 283 | ```cpp 284 | struct is_incrementable_r 285 | : tick::ops, tick::refines> 286 | { 287 | template 288 | auto require(T&& x) -> valid< 289 | decltype(x++), 290 | decltype(++x) 291 | >; 292 | }; 293 | ``` 294 | Notice, the placeholders have to be fully qualified here. 295 | 296 | -------------------------------------------------------------------------------- /doc/src/check.md: -------------------------------------------------------------------------------- 1 | Trait checking 2 | ============== 3 | 4 | The `TICK_TRAIT_CHECK` macro will statically assert the list of traits that are true but it will show what traits failed including base traits. This can be useful to show more informative messages about why a trait is false. 5 | 6 | -------------------------------------------------------------------------------- /doc/src/design.md: -------------------------------------------------------------------------------- 1 | Design Notes 2 | ============ 3 | 4 | Using template class 5 | -------------------- 6 | 7 | Tick uses the `valid` template class to place valid expressions, because it provides a more robust solution. Ideally, using tick we could define the traits like this: 8 | 9 | TICK_TRAIT(is_incrementable) 10 | { 11 | template 12 | auto require(T&& x) -> decltype( 13 | x++, 14 | ++x 15 | ); 16 | }; 17 | 18 | However, if one of the expressions returns a type that overloads the comma operator in a strange way(rare but still possible), then the trait could fail(ie return false when it should be true). To fix it, we could add `void` casts like this: 19 | 20 | TICK_TRAIT(is_incrementable) 21 | { 22 | template 23 | auto require(T&& x) -> decltype( 24 | (void)x++, 25 | (void)++x 26 | ); 27 | }; 28 | 29 | However, the `void` casts can be easy to forget. Another solution to the problem could be to pass it to a function: 30 | 31 | template 32 | void valid_expr(T&&...); 33 | 34 | TICK_TRAIT(is_incrementable) 35 | { 36 | template 37 | auto require(T&& x) -> decltype(valid_expr( 38 | x++, 39 | ++x 40 | )); 41 | }; 42 | 43 | However, if one of the expressions returns `void`, then this will fail as well(ie return false when it should be true). So this could be fixed in a similiar way as well: 44 | 45 | TICK_TRAIT(is_incrementable) 46 | { 47 | template 48 | auto require(T&& x) -> decltype(valid_expr( 49 | (x++, 1), 50 | (++x, 1) 51 | )); 52 | }; 53 | 54 | However, it can be easy to forget to put the `1` in there. So instead we use a `valid` template class, like this: 55 | 56 | TICK_TRAIT(is_incrementable) 57 | { 58 | template 59 | auto require(T&& x) -> valid< 60 | decltype(x++), 61 | decltype(++x) 62 | >; 63 | }; 64 | 65 | This requires placing each expression in a decltype, but if this was forgotten there would be a compile error pointing to the incorrect expression. 66 | 67 | Trait-based 68 | ----------- 69 | 70 | The concept predicates in Tick are defined as regular type traits(ie they are integrel constants) instead of a `constexpr bool` function. They are almost functionally the same in use. However, as a trait, it allows for better flexibility and expressiveness, through higher-order programming. This is what enables passing the traits to other functions which can be used to match return types to traits as well as other types. 71 | 72 | Specializations 73 | --------------- 74 | 75 | All the traits created can be specialized by the user. This is very important. Since the definition of traits relies on duck typing, there are times that even though it may quack like a duck it is not a duck. So with specialization the user can clarify the type's capabilities. 76 | 77 | -------------------------------------------------------------------------------- /doc/src/index.md: -------------------------------------------------------------------------------- 1 | 2 | Getting Started 3 | =============== 4 | 5 | Tick provides a mechanism for easily defining and using traits in C++11. For example, if we defined a generic `increment` function, like this: 6 | ```cpp 7 | template 8 | void increment(T& x) 9 | { 10 | x++; 11 | } 12 | ``` 13 | If we pass something that does not have the `++` operator to `increment`, we will get an error inside of the `increment` function. This can make it unclear whether the error is due to a mistake by the user of the function or by the implementor of the function. Instead we want to check the type requirements of the function. 14 | 15 | Using Tick we can create an `is_incrementable` trait, like this: 16 | ```cpp 17 | TICK_TRAIT(is_incrementable) 18 | { 19 | template 20 | auto require(T&& x) -> valid< 21 | decltype(x++), 22 | decltype(++x) 23 | >; 24 | }; 25 | ``` 26 | And then we can use a simple requires clause in our function to check the type requirements: 27 | ```cpp 28 | template())> 29 | void increment(T& x) 30 | { 31 | x++; 32 | } 33 | ``` 34 | So, now, if we pass something that is not incrementable to `increment`: 35 | ```cpp 36 | struct foo {}; 37 | 38 | foo f; 39 | increment(f); 40 | ``` 41 | Then we get an error like this in clang: 42 | 43 | demo.cpp:25:2: error: no matching function for call to 'increment' 44 | increment(f); 45 | ^~~~~~~~~ 46 | demo.cpp:14:19: note: candidate template ignored: disabled by 'enable_if' [with T = foo] 47 | template())> 48 | ^ 49 | 50 | This gives an error at the call to `increment` rather than inside the function, and then pointes to the type requirements of the function. This gives enough information for most commons cases, however, sometimes we may want more information. In that case the `TICK_TRAIT_CHECK` can be used. For example, say we had the `is_incrementable` trait defined like this: 51 | ```cpp 52 | TICK_TRAIT(is_incrementable, std::is_integral<_>) 53 | { 54 | template 55 | auto require(T&& x) -> valid< 56 | decltype(x++), 57 | decltype(++x) 58 | >; 59 | }; 60 | ``` 61 | Then if we use `TICK_TRAIT_CHECK`, we can see why `int*` is not incrementable: 62 | ```cpp 63 | TICK_TRAIT_CHECK(is_incrementable); 64 | ``` 65 | Which will produce this error: 66 | 67 | ../tick/trait_check.h:95:38: error: implicit instantiation of undefined template 'tick::TRAIT_CHECK_FAILURE, is_incrementable >' 68 | 69 | Which shows the traits that failed including any refinements. So we can see that it failed because `std::is_integral` is not true. 70 | 71 | -------------------------------------------------------------------------------- /doc/src/license.md: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /doc/src/requirements.md: -------------------------------------------------------------------------------- 1 | Requirements 2 | ============ 3 | 4 | This requires a C++11 compiler. There a no third-party dependencies. This has been tested on clang 3.4, gcc 4.6-4.9, and Visual Studio 2015. 5 | 6 | -------------------------------------------------------------------------------- /doc/src/requires.md: -------------------------------------------------------------------------------- 1 | Template constraints 2 | ==================== 3 | 4 | Three macros are provided to help improve the readability of template constraints. 5 | 6 | TICK_REQUIRES 7 | ------------- 8 | 9 | The `TICK_REQUIRES` can be used on template parameters. For example, 10 | ```cpp 11 | template())> 12 | void increment(T& x) 13 | { 14 | x++; 15 | } 16 | ``` 17 | 18 | TICK_CLASS_REQUIRES 19 | ------------------- 20 | 21 | The `TICK_CLASS_REQUIRES` can be used when template specialization is done on classes. For example, 22 | ```cpp 23 | template 24 | struct foo 25 | { 26 | ... 27 | }; 28 | 29 | template 30 | struct foo() and not std::is_integral())> 31 | { 32 | ... 33 | }; 34 | 35 | template 36 | struct foo())> 37 | { 38 | ... 39 | }; 40 | ``` 41 | 42 | TICK_MEMBER_REQUIRES 43 | -------------------- 44 | 45 | The `TICK_MEMBER_REQUIRES` can be used for member function inside of classes, that are not templated. For example, 46 | ```cpp 47 | template 48 | struct foo 49 | { 50 | T x; 51 | 52 | TICK_MEMBER_REQUIRES(is_incrementable()) 53 | void up() 54 | { 55 | x++; 56 | } 57 | }; 58 | ``` 59 | 60 | TICK_PARAM_REQUIRES 61 | -------------------- 62 | 63 | The `TICK_PARAM_REQUIRES` can be used in the paramater of the function. This is useful for lambdas: 64 | ```cpp 65 | auto increment = [](auto& x, TICK_PARAM_REQUIRES(is_incrementable())) 66 | { 67 | x++; 68 | }; 69 | ``` 70 | Also, the `trait` function is provided which can be used to deduce the type of the parameters: 71 | ```cpp 72 | auto increment = [](auto& x, TICK_PARAM_REQUIRES(trait(x))) 73 | { 74 | x++; 75 | }; 76 | ``` 77 | Note: The `trait` function always deduces the type without references. So `trait(x)` will always be false. 78 | 79 | TICK_FUNCTION_REQUIRES 80 | ---------------------- 81 | 82 | The `TICK_FUNCTION_REQUIRES` can be used on functions. This requires placing parenthesis around the return type: 83 | ```cpp 84 | template 85 | TICK_FUNCTION_REQUIRES(is_incrementable()) 86 | (void) increment(T& x) 87 | { 88 | x++; 89 | } 90 | ``` 91 | Note: The `TICK_REQUIRES` should be preferred. 92 | 93 | -------------------------------------------------------------------------------- /doc/src/tag.md: -------------------------------------------------------------------------------- 1 | Tag dispatching 2 | =============== 3 | 4 | Tag dispatching allows for functions to be ordered by the refinements defined in the trait. For example, if we try to implement an `advance` function like [`std::advance`](http://en.cppreference.com/w/cpp/iterator/advance). First, we can define the traits for the different traversals: 5 | 6 | ```cpp 7 | TICK_TRAIT(is_incrementable) 8 | { 9 | template 10 | auto require(T&& x) -> valid< 11 | decltype(x++), 12 | decltype(++x) 13 | >; 14 | }; 15 | 16 | TICK_TRAIT(is_decrementable, is_incrementable<_>) 17 | { 18 | template 19 | auto require(T&& x) -> valid< 20 | decltype(x--), 21 | decltype(--x) 22 | >; 23 | }; 24 | 25 | TICK_TRAIT(is_advanceable, is_decrementable<_>) 26 | { 27 | template 28 | auto require(T&& x, Number n) -> valid< 29 | decltype(x += n) 30 | >; 31 | }; 32 | ``` 33 | 34 | Then we can try to use template constraints for the different overloads: 35 | 36 | ```cpp 37 | template())> 38 | void advance(Iterator& it, int n) 39 | { 40 | it += n; 41 | } 42 | 43 | template())> 44 | void advance(Iterator& it, int n) 45 | { 46 | if (n > 0) while (n--) ++it; 47 | else 48 | { 49 | n *= -1; 50 | while (n--) --it; 51 | } 52 | } 53 | 54 | template())> 55 | void advance(Iterator& it, int n) 56 | { 57 | while (n--) ++it; 58 | } 59 | ``` 60 | 61 | However, this leads to ambiguities when we try to use it with iterators to vectors. That is because those iterators are valid for all three overloads. So, tag dispatching allows us to pick the overload that is the most refined. First, we need to call `most_refined` which will retrieve the tags for each each trait. So then `advance` could be implemented like this: 62 | 63 | ```cpp 64 | template 65 | void advance_impl(Iterator& it, int n, tick::tag) 66 | { 67 | it += n; 68 | } 69 | 70 | template 71 | void advance_impl(Iterator& it, int n, tick::tag) 72 | { 73 | if (n > 0) while (n--) ++it; 74 | else 75 | { 76 | n *= -1; 77 | while (n--) --it; 78 | } 79 | } 80 | 81 | template 82 | void advance_impl(Iterator& it, int n, tick::tag) 83 | { 84 | while (n--) ++it; 85 | } 86 | 87 | template 88 | void advance(Iterator& it, int n) 89 | { 90 | advance_impl(it, n, tick::most_refined>()); 91 | } 92 | ``` 93 | 94 | Specialization 95 | -------------- 96 | 97 | Tag dispatching will still work with specialization. Say, for instance, someone implemented an iterator called `foo_iterator` that when the user called `+=` it would crash at runtime. So we would like to specialize `is_advanceable` to make it false, so the `+=` won't be called: 98 | 99 | ```cpp 100 | template<> 101 | struct is_advanceable 102 | : std::false_type 103 | {}; 104 | ``` 105 | 106 | So this will exclude the `is_advanceable` overload, but the `is_decrementable` and `is_incrementable` will still be called. 107 | -------------------------------------------------------------------------------- /doc/src/traits.rst: -------------------------------------------------------------------------------- 1 | Traits 2 | ====== 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | 7 | ../../tick/traits/bare 8 | ../../tick/traits/is_allocator 9 | ../../tick/traits/is_associative_container 10 | ../../tick/traits/is_bidirectional_iterator 11 | ../../tick/traits/is_compare 12 | ../../tick/traits/is_container 13 | ../../tick/traits/is_copy_assignable 14 | ../../tick/traits/is_copy_constructible 15 | ../../tick/traits/is_copy_insertable 16 | ../../tick/traits/is_default_constructible 17 | ../../tick/traits/is_destructible 18 | ../../tick/traits/is_emplace_constructible 19 | ../../tick/traits/is_equality_comparable 20 | ../../tick/traits/is_erasable 21 | ../../tick/traits/is_forward_iterator 22 | ../../tick/traits/is_input_iterator 23 | ../../tick/traits/is_iterator 24 | ../../tick/traits/is_less_than_comparable 25 | ../../tick/traits/is_move_assignable 26 | ../../tick/traits/is_move_constructible 27 | ../../tick/traits/is_move_insertable 28 | ../../tick/traits/is_mutable_bidirectional_iterator 29 | ../../tick/traits/is_mutable_forward_iterator 30 | ../../tick/traits/is_mutable_random_access_iterator 31 | ../../tick/traits/is_nullable_pointer 32 | ../../tick/traits/is_output_iterator 33 | ../../tick/traits/is_pod 34 | ../../tick/traits/is_predicate 35 | ../../tick/traits/is_random_access_iterator 36 | ../../tick/traits/is_range 37 | ../../tick/traits/is_reversible_container 38 | ../../tick/traits/is_sequence_container 39 | ../../tick/traits/is_standard_layout 40 | ../../tick/traits/is_swappable 41 | ../../tick/traits/is_totally_ordered 42 | ../../tick/traits/is_trivial 43 | ../../tick/traits/is_trivially_copyable 44 | ../../tick/traits/is_value_swappable 45 | ../../tick/traits/is_weakly_ordered 46 | -------------------------------------------------------------------------------- /doc/src/zlang.md: -------------------------------------------------------------------------------- 1 | ZLang support 2 | ============= 3 | 4 | [ZLang](https://github.com/pfultz2/ZLang) is supported for some of the macros. The macros are in the `tick` namespace. For example, 5 | ```cpp 6 | $(trait is_incrementable) 7 | { 8 | template 9 | auto require(T&& x) -> valid< 10 | decltype(x++), 11 | decltype(++x) 12 | >; 13 | }; 14 | ``` 15 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Tick 2 | docs_dir: doc/src 3 | site_dir: doc/html/ 4 | repo_url: https://github.com/pfultz2/Tick 5 | use_directory_urls: false 6 | pages: 7 | - ['index.md', 'Home'] 8 | - ['builder.md', 'User Guide', 'Creating a Trait'] 9 | - ['requires.md', 'User Guide', 'Template constraints'] 10 | - ['check.md', 'User Guide', 'Checking a Trait'] 11 | - ['tag.md', 'User Guide', 'Tag dispatching'] 12 | - ['requirements.md', 'About', 'Requirements'] 13 | - ['acknowledgments.md', 'About', 'Acknowledgments'] 14 | - ['design.md', 'About', 'Design Notes'] 15 | - ['zlang.md', 'About', 'ZLang'] 16 | - ['license.md', 'About', 'License'] 17 | -------------------------------------------------------------------------------- /test/fold.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include 4 | #include 5 | 6 | template 7 | struct list {}; 8 | 9 | TICK_STATIC_TEST_CASE() 10 | { 11 | typedef list types; 12 | 13 | template 14 | struct op 15 | : std::conditional::value, 16 | std::integral_constant, 17 | State 18 | > 19 | {}; 20 | 21 | typedef tick::detail::fold< 22 | types, 23 | std::integral_constant, 24 | op 25 | >::type number_of_floats; 26 | 27 | static_assert(number_of_floats::value == 4, "Fold test failed"); 28 | }; 29 | -------------------------------------------------------------------------------- /test/integral_constant.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "test.h" 4 | #include 5 | 6 | TICK_STATIC_TEST_CASE() 7 | { 8 | struct true_type 9 | : tick::integral_constant 10 | {}; 11 | static_assert(true_type(), "Failed"); 12 | struct false_type 13 | : tick::integral_constant 14 | {}; 15 | static_assert(!false_type(), "Failed"); 16 | 17 | typedef tick::integral_constant one_type; 18 | typedef tick::integral_constant two_type; 19 | 20 | typedef decltype(!true_type()) not_true_type; 21 | static_assert(not_true_type::value == false, "Failed"); 22 | 23 | typedef decltype(true_type() && false_type()) true_type_and_false_type; 24 | static_assert(true_type_and_false_type::value == false, "Failed"); 25 | typedef decltype(true_type() || false_type()) true_type_or_false_type; 26 | static_assert(true_type_or_false_type::value == true, "Failed"); 27 | 28 | typedef decltype(!two_type()) not_two_type; 29 | static_assert(not_two_type::value == (!2), "Failed"); 30 | 31 | // GCC confuses the complement operator with the destructor 32 | #ifdef __clang__ 33 | typedef decltype(~two_type()) compl_two_type; 34 | static_assert(compl_two_type::value == (~2), "Failed"); 35 | #endif 36 | 37 | typedef decltype(+two_type()) unary_plus_two_type; 38 | static_assert(unary_plus_two_type::value == (+2), "Failed"); 39 | typedef decltype(-two_type()) unary_subtract_two_type; 40 | static_assert(unary_subtract_two_type::value == (-2), "Failed"); 41 | 42 | typedef decltype(one_type() + two_type()) one_type_add_two_type; 43 | static_assert(one_type_add_two_type::value == (1 + 2), "Failed"); 44 | typedef decltype(one_type() - two_type()) one_type_subtract_two_type; 45 | static_assert(one_type_subtract_two_type::value == (1 - 2), "Failed"); 46 | typedef decltype(one_type() * two_type()) one_type_multiply_two_type; 47 | static_assert(one_type_multiply_two_type::value == (1 * 2), "Failed"); 48 | typedef decltype(one_type() / two_type()) one_type_divide_two_type; 49 | static_assert(one_type_divide_two_type::value == (1 / 2), "Failed"); 50 | typedef decltype(one_type() % two_type()) one_type_remainder_two_type; 51 | static_assert(one_type_remainder_two_type::value == (1 % 2), "Failed"); 52 | typedef decltype(one_type() >> two_type()) one_type_shift_right_two_type; 53 | static_assert(one_type_shift_right_two_type::value == (1 >> 2), "Failed"); 54 | typedef decltype(one_type() << two_type()) one_type_shift_left_two_type; 55 | static_assert(one_type_shift_left_two_type::value == (1 << 2), "Failed"); 56 | typedef decltype(one_type() > two_type()) one_type_greater_than_two_type; 57 | static_assert(one_type_greater_than_two_type::value == (1 > 2), "Failed"); 58 | typedef decltype(one_type() < two_type()) one_type_less_than_two_type; 59 | static_assert(one_type_less_than_two_type::value == (1 < 2), "Failed"); 60 | typedef decltype(one_type() <= two_type()) one_type_less_than_equal_two_type; 61 | static_assert(one_type_less_than_equal_two_type::value == (1 <= 2), "Failed"); 62 | typedef decltype(one_type() >= two_type()) one_type_greater_than_equal_two_type; 63 | static_assert(one_type_greater_than_equal_two_type::value == (1 >= 2), "Failed"); 64 | typedef decltype(one_type() == two_type()) one_type_equal_two_type; 65 | static_assert(one_type_equal_two_type::value == (1 == 2), "Failed"); 66 | typedef decltype(one_type() != two_type()) one_type_not_equal_two_type; 67 | static_assert(one_type_not_equal_two_type::value == (1 != 2), "Failed"); 68 | typedef decltype(one_type() & two_type()) one_type_bit_and_two_type; 69 | static_assert(one_type_bit_and_two_type::value == (1 & 2), "Failed"); 70 | typedef decltype(one_type() ^ two_type()) one_type_xor_two_type; 71 | static_assert(one_type_xor_two_type::value == (1 ^ 2), "Failed"); 72 | typedef decltype(one_type() | two_type()) one_type_bit_or_two_type; 73 | static_assert(one_type_bit_or_two_type::value == (1 | 2), "Failed"); 74 | 75 | }; 76 | 77 | TICK_STATIC_TEST_CASE() 78 | { 79 | struct true_type 80 | : tick::integral_constant 81 | {}; 82 | static_assert(true_type(), "Failed"); 83 | struct false_type 84 | : tick::integral_constant 85 | {}; 86 | static_assert(!false_type(), "Failed"); 87 | 88 | typedef tick::integral_constant one_type; 89 | typedef tick::integral_constant two_type; 90 | 91 | typedef decltype(!true_type()) not_true_type; 92 | static_assert(not_true_type() == false, "Failed"); 93 | 94 | typedef decltype(true_type() && false_type()) true_type_and_false_type; 95 | static_assert(true_type_and_false_type() == false, "Failed"); 96 | typedef decltype(true_type() || false_type()) true_type_or_false_type; 97 | static_assert(true_type_or_false_type() == true, "Failed"); 98 | 99 | typedef decltype(!two_type()) not_two_type; 100 | static_assert(not_two_type() == (!2), "Failed"); 101 | 102 | // GCC confuses the complement operator with the destructor 103 | #ifdef __clang__ 104 | typedef decltype(~two_type()) compl_two_type; 105 | static_assert(compl_two_type() == (~2), "Failed"); 106 | #endif 107 | 108 | typedef decltype(+two_type()) unary_plus_two_type; 109 | static_assert(unary_plus_two_type() == (+2), "Failed"); 110 | typedef decltype(-two_type()) unary_subtract_two_type; 111 | static_assert(unary_subtract_two_type() == (-2), "Failed"); 112 | 113 | typedef decltype(one_type() + two_type()) one_type_add_two_type; 114 | static_assert(one_type_add_two_type() == (1 + 2), "Failed"); 115 | typedef decltype(one_type() - two_type()) one_type_subtract_two_type; 116 | static_assert(one_type_subtract_two_type() == (1 - 2), "Failed"); 117 | typedef decltype(one_type() * two_type()) one_type_multiply_two_type; 118 | static_assert(one_type_multiply_two_type() == (1 * 2), "Failed"); 119 | typedef decltype(one_type() / two_type()) one_type_divide_two_type; 120 | static_assert(one_type_divide_two_type() == (1 / 2), "Failed"); 121 | typedef decltype(one_type() % two_type()) one_type_remainder_two_type; 122 | static_assert(one_type_remainder_two_type() == (1 % 2), "Failed"); 123 | typedef decltype(one_type() >> two_type()) one_type_shift_right_two_type; 124 | static_assert(one_type_shift_right_two_type() == (1 >> 2), "Failed"); 125 | typedef decltype(one_type() << two_type()) one_type_shift_left_two_type; 126 | static_assert(one_type_shift_left_two_type() == (1 << 2), "Failed"); 127 | typedef decltype(one_type() > two_type()) one_type_greater_than_two_type; 128 | static_assert(one_type_greater_than_two_type() == (1 > 2), "Failed"); 129 | typedef decltype(one_type() < two_type()) one_type_less_than_two_type; 130 | static_assert(one_type_less_than_two_type() == (1 < 2), "Failed"); 131 | typedef decltype(one_type() <= two_type()) one_type_less_than_equal_two_type; 132 | static_assert(one_type_less_than_equal_two_type() == (1 <= 2), "Failed"); 133 | typedef decltype(one_type() >= two_type()) one_type_greater_than_equal_two_type; 134 | static_assert(one_type_greater_than_equal_two_type() == (1 >= 2), "Failed"); 135 | typedef decltype(one_type() == two_type()) one_type_equal_two_type; 136 | static_assert(one_type_equal_two_type() == (1 == 2), "Failed"); 137 | typedef decltype(one_type() != two_type()) one_type_not_equal_two_type; 138 | static_assert(one_type_not_equal_two_type() == (1 != 2), "Failed"); 139 | typedef decltype(one_type() & two_type()) one_type_bit_and_two_type; 140 | static_assert(one_type_bit_and_two_type() == (1 & 2), "Failed"); 141 | typedef decltype(one_type() ^ two_type()) one_type_xor_two_type; 142 | static_assert(one_type_xor_two_type() == (1 ^ 2), "Failed"); 143 | typedef decltype(one_type() | two_type()) one_type_bit_or_two_type; 144 | static_assert(one_type_bit_or_two_type() == (1 | 2), "Failed"); 145 | 146 | }; 147 | 148 | TICK_STATIC_TEST_CASE() 149 | { 150 | struct true_type 151 | : tick::integral_constant 152 | {}; 153 | static_assert(true_type(), "Failed"); 154 | struct false_type 155 | : tick::integral_constant 156 | {}; 157 | static_assert(!false_type(), "Failed"); 158 | 159 | typedef tick::integral_constant one_type; 160 | typedef tick::integral_constant two_type; 161 | 162 | static_assert((!true_type()) == false, "Failed"); 163 | 164 | static_assert((true_type() && false_type()) == false, "Failed"); 165 | static_assert((true_type() || false_type()) == true, "Failed"); 166 | 167 | static_assert((!two_type()) == (!2), "Failed"); 168 | 169 | // GCC confuses the complement operator with the destructor 170 | #ifdef __clang__ 171 | static_assert((~two_type()) == (~2), "Failed"); 172 | #endif 173 | 174 | static_assert((+two_type()) == (+2), "Failed"); 175 | static_assert((-two_type()) == (-2), "Failed"); 176 | 177 | static_assert((one_type() + two_type()) == (1 + 2), "Failed"); 178 | static_assert((one_type() - two_type()) == (1 - 2), "Failed"); 179 | static_assert((one_type() * two_type()) == (1 * 2), "Failed"); 180 | static_assert((one_type() / two_type()) == (1 / 2), "Failed"); 181 | static_assert((one_type() % two_type()) == (1 % 2), "Failed"); 182 | static_assert((one_type() >> two_type()) == (1 >> 2), "Failed"); 183 | static_assert((one_type() << two_type()) == (1 << 2), "Failed"); 184 | static_assert((one_type() > two_type()) == (1 > 2), "Failed"); 185 | static_assert((one_type() < two_type()) == (1 < 2), "Failed"); 186 | static_assert((one_type() <= two_type()) == (1 <= 2), "Failed"); 187 | static_assert((one_type() >= two_type()) == (1 >= 2), "Failed"); 188 | static_assert((one_type() == two_type()) == (1 == 2), "Failed"); 189 | static_assert((one_type() != two_type()) == (1 != 2), "Failed"); 190 | static_assert((one_type() & two_type()) == (1 & 2), "Failed"); 191 | static_assert((one_type() ^ two_type()) == (1 ^ 2), "Failed"); 192 | static_assert((one_type() | two_type()) == (1 | 2), "Failed"); 193 | 194 | }; 195 | 196 | TICK_STATIC_TEST_CASE() 197 | { 198 | typedef tick::integral_constant one_type; 199 | typedef std::integral_constant one_type_std; 200 | 201 | typedef decltype(one_type() == one_type_std()) result_type; 202 | static_assert(result_type::value, "Failed"); 203 | }; 204 | -------------------------------------------------------------------------------- /test/matches.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "test.h" 4 | #include 5 | #include 6 | 7 | template 8 | struct replace_args_test 9 | {}; 10 | 11 | TICK_TEST_CASE() 12 | { 13 | STATIC_ASSERT_SAME(typename tick::detail::replace_args, long>::type, 14 | replace_args_test); 15 | STATIC_ASSERT_SAME(typename tick::detail::replace_args, long>::type, 16 | replace_args_test); 17 | STATIC_ASSERT_SAME(typename tick::detail::replace_args, long>::type, 18 | replace_args_test); 19 | STATIC_ASSERT_SAME(typename tick::detail::replace_args, long, float>::type, 20 | replace_args_test); 21 | STATIC_ASSERT_SAME(typename tick::detail::replace_args, long>::type, 22 | replace_args_test); 23 | STATIC_ASSERT_SAME(typename tick::detail::replace_args, long>::type, 24 | replace_args_test); 25 | } 26 | 27 | TICK_TEST_CASE() 28 | { 29 | static_assert(tick::detail::matches::value, "int -> int doesn't match"); 30 | static_assert(tick::detail::matches::value, "int -> void doesn't match"); 31 | static_assert(tick::detail::matches::value, "void -> void doesn't match"); 32 | 33 | static_assert(!tick::detail::matches::value, "int -> int& shouldn't match"); 34 | static_assert(tick::detail::matches::value, "int -> const int& doesn't match"); 35 | static_assert(tick::detail::matches::value, "int -> const float& doesn't match"); 36 | 37 | static_assert(tick::detail::matches::iterator, std::vector::const_iterator>::value, 38 | "std::vector::iterator -> std::vector::const_iterator doesn't match"); 39 | 40 | static_assert(tick::detail::matches::iterator, const std::vector::const_iterator&>::value, 41 | "std::vector::iterator -> std::vector::const_iterator& doesn't match"); 42 | 43 | static_assert(tick::detail::matches, int>::value, "is_integral failed"); 44 | static_assert(tick::detail::matches, float>::value, "is_integral failed"); 45 | static_assert(tick::detail::matches, void>::value, "is_integral failed"); 46 | } 47 | -------------------------------------------------------------------------------- /test/requires.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include 4 | #include 5 | #include 6 | 7 | struct not_int {}; 8 | 9 | template 10 | struct tick_is_integral 11 | : tick::integral_constant::value)> 12 | { 13 | constexpr tick_is_integral() 14 | {} 15 | }; 16 | TICK_STATIC_TEST_CASE() 17 | { 18 | template::value)> 19 | static std::true_type check_requires(T); 20 | 21 | template::value)> 22 | static std::false_type check_requires(T); 23 | 24 | STATIC_ASSERT_SAME(decltype(check_requires(1)), std::true_type); 25 | STATIC_ASSERT_SAME(decltype(check_requires(not_int())), std::false_type); 26 | }; 27 | 28 | TICK_STATIC_TEST_CASE() 29 | { 30 | template::value)> 31 | static std::true_type check_requires(T); 32 | 33 | template::value)> 34 | static std::true_type check_requires(T); 35 | 36 | STATIC_ASSERT_SAME(decltype(check_requires(1)), std::true_type); 37 | STATIC_ASSERT_SAME(decltype(check_requires(not_int())), std::true_type); 38 | }; 39 | 40 | TICK_STATIC_TEST_CASE() 41 | { 42 | template::value)> 43 | static std::true_type check_vardiac_requires(T, Ts...); 44 | 45 | template::value)> 46 | static std::false_type check_vardiac_requires(T, Ts...); 47 | 48 | STATIC_ASSERT_SAME(decltype(check_vardiac_requires(1)), std::true_type); 49 | STATIC_ASSERT_SAME(decltype(check_vardiac_requires(not_int())), std::false_type); 50 | }; 51 | 52 | TICK_STATIC_TEST_CASE() 53 | { 54 | template())> 55 | static std::true_type check_requires(T); 56 | 57 | template())> 58 | static std::false_type check_requires(T); 59 | 60 | STATIC_ASSERT_SAME(decltype(check_requires(1)), std::true_type); 61 | STATIC_ASSERT_SAME(decltype(check_requires(not_int())), std::false_type); 62 | }; 63 | 64 | TICK_STATIC_TEST_CASE() 65 | { 66 | template())> 67 | static std::true_type check_requires(T); 68 | 69 | template())> 70 | static std::true_type check_requires(T); 71 | 72 | STATIC_ASSERT_SAME(decltype(check_requires(1)), std::true_type); 73 | STATIC_ASSERT_SAME(decltype(check_requires(not_int())), std::true_type); 74 | }; 75 | 76 | TICK_STATIC_TEST_CASE() 77 | { 78 | template())> 79 | static std::true_type check_vardiac_requires(T, Ts...); 80 | 81 | template())> 82 | static std::false_type check_vardiac_requires(T, Ts...); 83 | 84 | STATIC_ASSERT_SAME(decltype(check_vardiac_requires(1)), std::true_type); 85 | STATIC_ASSERT_SAME(decltype(check_vardiac_requires(not_int())), std::false_type); 86 | }; 87 | template 88 | TICK_FUNCTION_REQUIRES(std::is_integral::value) 89 | (std::true_type) check_function_requires_c(T); 90 | 91 | template 92 | TICK_FUNCTION_REQUIRES(!std::is_integral::value) 93 | (std::false_type) check_function_requires_c(T); 94 | 95 | TICK_STATIC_TEST_CASE() 96 | { 97 | STATIC_ASSERT_SAME(decltype(check_function_requires_c(1)), std::true_type); 98 | STATIC_ASSERT_SAME(decltype(check_function_requires_c(not_int())), std::false_type); 99 | }; 100 | 101 | template 102 | TICK_FUNCTION_REQUIRES(tick_is_integral()) 103 | (std::true_type) check_function_requires(T); 104 | 105 | template 106 | TICK_FUNCTION_REQUIRES(!tick_is_integral()) 107 | (std::false_type) check_function_requires(T); 108 | 109 | TICK_STATIC_TEST_CASE() 110 | { 111 | STATIC_ASSERT_SAME(decltype(check_function_requires(1)), std::true_type); 112 | STATIC_ASSERT_SAME(decltype(check_function_requires(not_int())), std::false_type); 113 | }; 114 | 115 | TICK_STATIC_TEST_CASE() 116 | { 117 | template 118 | struct check_class_requires; 119 | 120 | template 121 | struct check_class_requires::value)> 122 | { 123 | static std::true_type call(); 124 | }; 125 | 126 | template 127 | struct check_class_requires::value)> 128 | { 129 | static std::false_type call(); 130 | }; 131 | 132 | STATIC_ASSERT_SAME(decltype(check_class_requires::call()), std::true_type); 133 | STATIC_ASSERT_SAME(decltype(check_class_requires::call()), std::false_type); 134 | }; 135 | 136 | TICK_STATIC_TEST_CASE() 137 | { 138 | template 139 | struct check_class_requires; 140 | 141 | template 142 | struct check_class_requires())> 143 | { 144 | static std::true_type call(); 145 | }; 146 | 147 | template 148 | struct check_class_requires())> 149 | { 150 | static std::false_type call(); 151 | }; 152 | 153 | STATIC_ASSERT_SAME(decltype(check_class_requires::call()), std::true_type); 154 | STATIC_ASSERT_SAME(decltype(check_class_requires::call()), std::false_type); 155 | }; 156 | 157 | TICK_STATIC_TEST_CASE() 158 | { 159 | template 160 | struct check_member_requires 161 | { 162 | T x; 163 | 164 | TICK_MEMBER_REQUIRES(std::is_integral::value) 165 | std::true_type foo() 166 | { 167 | x += 1; 168 | return std::true_type(); 169 | } 170 | 171 | TICK_MEMBER_REQUIRES(!std::is_integral::value) 172 | std::false_type foo() 173 | { 174 | return std::false_type(); 175 | } 176 | }; 177 | 178 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), std::true_type); 179 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), std::false_type); 180 | }; 181 | 182 | TICK_STATIC_TEST_CASE() 183 | { 184 | template 185 | struct check_member_requires 186 | { 187 | T x; 188 | 189 | TICK_MEMBER_REQUIRES(std::is_integral::value) 190 | int foo() 191 | { 192 | x += 1; 193 | return x; 194 | } 195 | 196 | TICK_MEMBER_REQUIRES(!std::is_integral::value) 197 | int foo() 198 | { 199 | return 0; 200 | } 201 | }; 202 | 203 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), int); 204 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), int); 205 | }; 206 | 207 | TICK_STATIC_TEST_CASE() 208 | { 209 | template 210 | struct check_member_requires 211 | { 212 | T x; 213 | 214 | TICK_MEMBER_REQUIRES(tick_is_integral()) 215 | std::true_type foo() 216 | { 217 | x += 1; 218 | return std::true_type(); 219 | } 220 | 221 | TICK_MEMBER_REQUIRES(!tick_is_integral()) 222 | std::false_type foo() 223 | { 224 | return std::false_type(); 225 | } 226 | }; 227 | 228 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), std::true_type); 229 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), std::false_type); 230 | }; 231 | 232 | TICK_STATIC_TEST_CASE() 233 | { 234 | template 235 | struct check_member_requires 236 | { 237 | T x; 238 | 239 | TICK_MEMBER_REQUIRES(tick_is_integral()) 240 | int foo() 241 | { 242 | x += 1; 243 | return x; 244 | } 245 | 246 | TICK_MEMBER_REQUIRES(!tick_is_integral()) 247 | int foo() 248 | { 249 | return 0; 250 | } 251 | }; 252 | 253 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), int); 254 | STATIC_ASSERT_SAME(decltype(check_member_requires().foo()), int); 255 | }; 256 | 257 | // template 258 | // struct is_integral 259 | // : tick::integral_constant::value> 260 | // {}; 261 | 262 | template 263 | std::true_type check_param_requires(T, TICK_PARAM_REQUIRES(tick_is_integral())); 264 | 265 | template 266 | std::false_type check_param_requires(T, TICK_PARAM_REQUIRES(!tick_is_integral())); 267 | 268 | TICK_STATIC_TEST_CASE() 269 | { 270 | STATIC_ASSERT_SAME(decltype(check_param_requires(1)), std::true_type); 271 | STATIC_ASSERT_SAME(decltype(check_param_requires(not_int())), std::false_type); 272 | }; 273 | 274 | TICK_STATIC_TEST_CASE() 275 | { 276 | static const int x = 1; 277 | typedef decltype(tick::trait(x)) test_type; 278 | static_assert(test_type::value, "Trait test failed"); 279 | }; 280 | 281 | template 282 | std::true_type check_param_trait_requires(T x, TICK_PARAM_REQUIRES(tick::trait(x))); 283 | 284 | template 285 | std::false_type check_param_trait_requires(T x, TICK_PARAM_REQUIRES(!tick::trait(x))); 286 | 287 | TICK_STATIC_TEST_CASE() 288 | { 289 | STATIC_ASSERT_SAME(decltype(check_param_trait_requires(1)), std::true_type); 290 | STATIC_ASSERT_SAME(decltype(check_param_trait_requires(not_int())), std::false_type); 291 | }; 292 | -------------------------------------------------------------------------------- /test/set.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include 4 | #include 5 | 6 | TICK_STATIC_TEST_CASE() 7 | { 8 | typedef tick::detail::set set1; 9 | typedef typename tick::detail::set_insert::type set2; 10 | STATIC_ASSERT_SAME(set1, set2); 11 | }; 12 | 13 | TICK_STATIC_TEST_CASE() 14 | { 15 | typedef tick::detail::set set1; 16 | typedef typename tick::detail::set_insert::type set2; 17 | typedef tick::detail::set set3; 18 | STATIC_ASSERT_SAME(set3, set2); 19 | }; 20 | -------------------------------------------------------------------------------- /test/tag.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef TICK_HAS_COPY_CONSTRUCTIBLE_TRAIT 8 | # if defined (__GNUC__) && !defined (__clang__) 9 | # if __GNUC__ == 4 && __GNUC_MINOR__ < 7 10 | # define TICK_HAS_COPY_CONSTRUCTIBLE_TRAIT 0 11 | # else 12 | # define TICK_HAS_COPY_CONSTRUCTIBLE_TRAIT 1 13 | # endif 14 | # else 15 | # define TICK_HAS_COPY_CONSTRUCTIBLE_TRAIT 1 16 | # endif 17 | #endif 18 | 19 | TICK_TRAIT(is_incrementable) 20 | { 21 | template 22 | auto require(T&& x) -> valid< 23 | decltype(x++), 24 | decltype(++x) 25 | >; 26 | }; 27 | 28 | TICK_TRAIT(is_decrementable, is_incrementable<_>) 29 | { 30 | template 31 | auto require(T&& x) -> valid< 32 | decltype(x--), 33 | decltype(--x) 34 | >; 35 | }; 36 | 37 | TICK_TRAIT(is_advanceable, is_decrementable<_>) 38 | { 39 | template 40 | auto require(T&& x, Number n) -> valid< 41 | decltype(x += n) 42 | >; 43 | }; 44 | 45 | TICK_TRAIT(is_numeric, is_incrementable<_>, is_decrementable<_>, is_advanceable<_, int>) 46 | { 47 | }; 48 | 49 | TICK_STATIC_TEST_CASE() 50 | { 51 | typedef typename is_advanceable::type::tick_trait_refinements check_refines; 52 | typedef typename tick::detail::get_refinements>::type advanceable_refinements; 53 | static_assert(std::is_same(), "Refinements don't match"); 54 | static_assert(not std::is_same>(), "Empty refinements"); 55 | }; 56 | 57 | TICK_STATIC_TEST_CASE() 58 | { 59 | static_assert(std::is_base_of, tick::tag>(), "Not tag base"); 60 | static_assert(std::is_base_of, tick::tag>(), "Not tag base"); 61 | static_assert(std::is_base_of, tick::tag>(), "Not tag base"); 62 | }; 63 | 64 | TICK_STATIC_TEST_CASE() 65 | { 66 | static_assert(is_numeric(), "Not numeric"); 67 | static_assert(is_advanceable(), "Not advanceable"); 68 | static_assert(is_decrementable(), "Not decrementable"); 69 | static_assert(is_incrementable(), "Not incrementable"); 70 | 71 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 72 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 73 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 74 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 75 | 76 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 77 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 78 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 79 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 80 | 81 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 82 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 83 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 84 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 85 | }; 86 | 87 | template 88 | void advance_impl(Iterator& it, int n, tick::tag) 89 | { 90 | it += n; 91 | } 92 | 93 | template 94 | void advance_impl(Iterator& it, int n, tick::tag) 95 | { 96 | if (n > 0) while (n--) ++it; 97 | else 98 | { 99 | n *= -1; 100 | while (n--) --it; 101 | } 102 | } 103 | 104 | template 105 | void advance_impl(Iterator& it, int n, tick::tag) 106 | { 107 | while (n--) ++it; 108 | } 109 | 110 | template 111 | void advance(Iterator& it, int n) 112 | { 113 | advance_impl(it, n, tick::most_refined>()); 114 | } 115 | 116 | TICK_TEST_CASE() 117 | { 118 | std::list l = { 1, 2, 3, 4, 5, 6 }; 119 | auto iterator = l.begin(); 120 | advance(iterator, 4); 121 | TICK_TEST_CHECK(*iterator == 5); 122 | } 123 | 124 | TICK_TEST_CASE() 125 | { 126 | std::list l = { 1, 2, 3, 4, 5, 6 }; 127 | auto iterator = l.end(); 128 | advance(iterator, -4); 129 | TICK_TEST_CHECK(*iterator == 3); 130 | } 131 | 132 | TICK_TEST_CASE() 133 | { 134 | std::vector v = { 1, 2, 3, 4, 5, 6 }; 135 | auto iterator = v.begin(); 136 | advance(iterator, 4); 137 | TICK_TEST_CHECK(*iterator == 5); 138 | } 139 | 140 | template 141 | void advance_numeric(Iterator& it, int n) 142 | { 143 | advance_impl(it, n, tick::most_refined>()); 144 | } 145 | 146 | TICK_TEST_CASE() 147 | { 148 | std::list l = { 1, 2, 3, 4, 5, 6 }; 149 | auto iterator = l.begin(); 150 | advance_numeric(iterator, 4); 151 | TICK_TEST_CHECK(*iterator == 5); 152 | } 153 | 154 | TICK_TEST_CASE() 155 | { 156 | std::list l = { 1, 2, 3, 4, 5, 6 }; 157 | auto iterator = l.end(); 158 | advance_numeric(iterator, -4); 159 | TICK_TEST_CHECK(*iterator == 3); 160 | } 161 | 162 | TICK_TEST_CASE() 163 | { 164 | std::vector v = { 1, 2, 3, 4, 5, 6 }; 165 | auto iterator = v.begin(); 166 | advance_numeric(iterator, 4); 167 | TICK_TEST_CHECK(*iterator == 5); 168 | } 169 | 170 | #if TICK_HAS_COPY_CONSTRUCTIBLE_TRAIT 171 | TICK_TRAIT(is_integral_incrementable, std::is_integral<_>, std::is_copy_constructible<_>) 172 | { 173 | template 174 | auto require(T&& x) -> decltype(x++); 175 | }; 176 | 177 | TICK_STATIC_TEST_CASE() 178 | { 179 | static_assert(std::is_base_of, tick::tag>(), "Not tag base"); 180 | static_assert(std::is_base_of, tick::tag>(), "Not tag base"); 181 | static_assert(std::is_base_of, tick::tag>(), "Not tag base"); 182 | 183 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 184 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 185 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 186 | 187 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 188 | static_assert(not std::is_base_of, tick::most_refined>>(), "Not tag base"); 189 | static_assert(std::is_base_of, tick::most_refined>>(), "Not tag base"); 190 | }; 191 | #endif 192 | 193 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | #ifndef GUARD_TEST_H 2 | #define GUARD_TEST_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace tick { namespace test { 11 | typedef std::function test_case; 12 | static std::vector test_cases; 13 | 14 | struct auto_register 15 | { 16 | auto_register(test_case tc) 17 | { 18 | test_cases.push_back(tc); 19 | } 20 | }; 21 | 22 | #define TICK_DETAIL_TEST_CASE(name) \ 23 | struct name \ 24 | { void operator()() const; }; \ 25 | static tick::test::auto_register TICK_PP_CAT(name, _register) = tick::test::auto_register(name()); \ 26 | void name::operator()() const 27 | }} 28 | 29 | #define STATIC_ASSERT_SAME(...) static_assert(std::is_same<__VA_ARGS__>::value, "Types are not the same") 30 | #define TICK_TEST_CASE() TICK_DETAIL_TEST_CASE(TICK_PP_CAT(test_, __LINE__)) 31 | #define TICK_TEST_CHECK(...) if (!(__VA_ARGS__)) std::cout << "*****FAILED: " << #__VA_ARGS__ << "@" << __FILE__ << ": " << __LINE__ << std::endl 32 | #define TICK_STATIC_TEST_CASE() struct TICK_PP_CAT(test_, __LINE__) 33 | 34 | #define TICK_TEST_TEMPLATE(...) typedef std::integral_constant TICK_PP_CAT(test_template_, __LINE__) 35 | 36 | 37 | int main() 38 | { 39 | for(const auto& tc: tick::test::test_cases) tc(); 40 | return 0; 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /test/trait_check.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include 4 | 5 | TICK_TRAIT(is_incrementable) 6 | { 7 | template 8 | auto require(T&& x) -> valid< 9 | decltype(x++) 10 | >; 11 | }; 12 | 13 | TICK_TRAIT(is_integer_incrementable, is_incrementable<_>, std::is_integral<_>) 14 | { 15 | }; 16 | 17 | #define TRAIT_CHECK_SUCCESS(...) \ 18 | static_assert(std::is_same::type, tick::TRAIT_CHECK_FAILURE<>>::value, "Trait check failure") 19 | 20 | #define TRAIT_CHECK_FAIL(...) \ 21 | static_assert(not std::is_same::type, tick::TRAIT_CHECK_FAILURE<>>::value, "Trait check failure") 22 | 23 | TICK_STATIC_TEST_CASE() 24 | { 25 | TICK_TRAIT_CHECK(is_incrementable, is_incrementable); 26 | TICK_TRAIT_CHECK(is_integer_incrementable); 27 | 28 | TRAIT_CHECK_SUCCESS(is_incrementable, is_incrementable); 29 | TRAIT_CHECK_SUCCESS(is_integer_incrementable); 30 | 31 | TRAIT_CHECK_FAIL(is_integer_incrementable, is_integer_incrementable); 32 | }; 33 | -------------------------------------------------------------------------------- /test/traits.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | TICK_STATIC_TEST_CASE() 16 | { 17 | 18 | TICK_TRAIT_CHECK(tick::is_equality_comparable); 19 | TICK_TRAIT_CHECK(tick::is_weakly_ordered); 20 | TICK_TRAIT_CHECK(tick::is_totally_ordered); 21 | 22 | TICK_TRAIT_CHECK(tick::is_equality_comparable); 23 | TICK_TRAIT_CHECK(tick::is_weakly_ordered); 24 | TICK_TRAIT_CHECK(tick::is_totally_ordered); 25 | 26 | TICK_TRAIT_CHECK(tick::is_swappable); 27 | TICK_TRAIT_CHECK(tick::is_swappable); 28 | 29 | TICK_TRAIT_CHECK(tick::is_nullable_pointer); 30 | TICK_TRAIT_CHECK(tick::is_nullable_pointer>); 31 | 32 | TICK_TRAIT_CHECK(tick::is_input_iterator>); 33 | TICK_TRAIT_CHECK(tick::is_iterator>>); 34 | TICK_TRAIT_CHECK(tick::is_output_iterator>, int>); 35 | 36 | TICK_TRAIT_CHECK(tick::is_iterator::const_iterator>); 37 | TICK_TRAIT_CHECK(tick::is_forward_iterator::const_iterator>); 38 | TICK_TRAIT_CHECK(tick::is_bidirectional_iterator::const_iterator>); 39 | TICK_TRAIT_CHECK(tick::is_mutable_bidirectional_iterator::iterator>); 40 | static_assert(not tick::is_mutable_bidirectional_iterator::const_iterator>(), "Const iterator mutable"); 41 | static_assert(not tick::is_mutable_random_access_iterator::const_iterator>(), "List const iterator is mutable and has random access"); 42 | static_assert(not tick::is_random_access_iterator::iterator>(), "List iterator has random access"); 43 | 44 | TICK_TRAIT_CHECK(tick::is_random_access_iterator::const_iterator>); 45 | TICK_TRAIT_CHECK(tick::is_mutable_random_access_iterator::iterator>); 46 | static_assert(not tick::is_mutable_random_access_iterator::const_iterator>(), "Const iterator mutable"); 47 | 48 | TICK_TRAIT_CHECK(tick::is_iterator); 49 | TICK_TRAIT_CHECK(tick::is_input_iterator); 50 | TICK_TRAIT_CHECK(tick::is_output_iterator); 51 | TICK_TRAIT_CHECK(tick::is_forward_iterator); 52 | TICK_TRAIT_CHECK(tick::is_bidirectional_iterator); 53 | TICK_TRAIT_CHECK(tick::is_mutable_bidirectional_iterator); 54 | TICK_TRAIT_CHECK(tick::is_mutable_random_access_iterator); 55 | TICK_TRAIT_CHECK(tick::is_random_access_iterator); 56 | 57 | TICK_TRAIT_CHECK(tick::is_iterator); 58 | TICK_TRAIT_CHECK(tick::is_input_iterator); 59 | TICK_TRAIT_CHECK(tick::is_output_iterator); 60 | TICK_TRAIT_CHECK(tick::is_forward_iterator); 61 | TICK_TRAIT_CHECK(tick::is_bidirectional_iterator); 62 | TICK_TRAIT_CHECK(tick::is_mutable_bidirectional_iterator); 63 | TICK_TRAIT_CHECK(tick::is_mutable_random_access_iterator); 64 | TICK_TRAIT_CHECK(tick::is_random_access_iterator); 65 | 66 | TICK_TRAIT_CHECK(tick::is_value_swappable::iterator>); 67 | TICK_TRAIT_CHECK(tick::is_value_swappable::iterator>); 68 | }; 69 | 70 | TICK_STATIC_TEST_CASE() 71 | { 72 | TICK_TRAIT_CHECK(tick::is_allocator>); 73 | }; 74 | 75 | TICK_STATIC_TEST_CASE() 76 | { 77 | TICK_TRAIT_CHECK(tick::is_range>); 78 | TICK_TRAIT_CHECK(tick::is_range>); 79 | TICK_TRAIT_CHECK(tick::is_range>); 80 | TICK_TRAIT_CHECK(tick::is_range>); 81 | 82 | 83 | TICK_TRAIT_CHECK(tick::is_container>); 84 | TICK_TRAIT_CHECK(tick::is_container>); 85 | TICK_TRAIT_CHECK(tick::is_container>); 86 | TICK_TRAIT_CHECK(tick::is_container>); 87 | TICK_TRAIT_CHECK(tick::is_container); 88 | 89 | TICK_TRAIT_CHECK(tick::is_reversible_container>); 90 | TICK_TRAIT_CHECK(tick::is_reversible_container>); 91 | TICK_TRAIT_CHECK(tick::is_reversible_container>); 92 | TICK_TRAIT_CHECK(tick::is_reversible_container>); 93 | 94 | TICK_TRAIT_CHECK(tick::is_sequence_container>); 95 | TICK_TRAIT_CHECK(tick::is_sequence_container>); 96 | TICK_TRAIT_CHECK(tick::is_sequence_container>); 97 | TICK_TRAIT_CHECK(tick::is_sequence_container); 98 | 99 | static_assert(!tick::is_sequence_container>(), "Not a sequence container"); 100 | // Dont check against a set, since it can almost look like a sequence container 101 | // static_assert(!tick::is_sequence_container>(), "Not a sequence container"); 102 | 103 | TICK_TRAIT_CHECK(tick::is_associative_container>); 104 | TICK_TRAIT_CHECK(tick::is_associative_container>); 105 | TICK_TRAIT_CHECK(tick::is_associative_container>); 106 | TICK_TRAIT_CHECK(tick::is_associative_container>); 107 | 108 | static_assert(!tick::is_associative_container>(), "Not a associative container"); 109 | static_assert(!tick::is_associative_container>(), "Not a associative container"); 110 | }; 111 | 112 | -------------------------------------------------------------------------------- /tick.pc.in: -------------------------------------------------------------------------------- 1 | Name: Tick 2 | Description: Trait introspection and concept creator for C++11 3 | URL: https://github.com/pfultz2/Tick 4 | Version: @Tick_VERSION_MAJOR@.@Tick_VERSION_MINOR@ 5 | 6 | Cflags: -I@CMAKE_INSTALL_PREFIX@/include 7 | -------------------------------------------------------------------------------- /tick/builder.h: -------------------------------------------------------------------------------- 1 | /*============================================================================= 2 | Copyright (c) 2014 Paul Fultz II 3 | builder.h 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | ==============================================================================*/ 7 | 8 | #ifndef TICK_GUARD_BUILDER_H 9 | #define TICK_GUARD_BUILDER_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace tick { 17 | 18 | namespace detail { 19 | 20 | struct no_check {}; 21 | 22 | template 23 | struct id { typedef T type; }; 24 | 25 | template class... Templates> 26 | struct template_holder 27 | { 28 | typedef void type; 29 | }; 30 | 31 | #ifdef _MSC_VER 32 | template 33 | struct fast_and; 34 | 35 | template 36 | struct fast_and 37 | : tick::integral_constant::value)> 38 | {}; 39 | 40 | template<> 41 | struct fast_and<> 42 | : tick::true_type 43 | {}; 44 | 45 | template 46 | struct fast_or; 47 | 48 | template 49 | struct fast_or 50 | : tick::integral_constant::value)> 51 | {}; 52 | 53 | template<> 54 | struct fast_or<> 55 | : tick::false_type 56 | {}; 57 | #else 58 | template struct bool_seq {}; 59 | template 60 | TICK_USING(fast_and, bool_< 61 | std::is_same< 62 | detail::bool_seq, 63 | detail::bool_seq<(Traits::value, true)...> 64 | >::type::value 65 | >); 66 | 67 | template 68 | TICK_USING(fast_or, bool_< 69 | !std::is_same< 70 | detail::bool_seq, 71 | detail::bool_seq<(Traits::value && false)...> 72 | >::type::value 73 | >); 74 | #endif 75 | 76 | template 77 | TICK_USING(bare, std::remove_cv::type>); 78 | 79 | template 80 | struct is_void 81 | : std::is_void 82 | {}; 83 | 84 | template 85 | struct is_void> 86 | : tick::true_type 87 | {}; 88 | 89 | template 90 | struct is_void> 91 | : tick::true_type 92 | {}; 93 | 94 | struct base_requires 95 | { 96 | template 97 | int require(Ts&&...); 98 | }; 99 | 100 | template 101 | struct always_false 102 | : tick::false_type 103 | {}; 104 | 105 | template 106 | // Template alias only works on clang 107 | #ifdef __clang__ 108 | using multi_match = fast_and...>; 109 | #else 110 | struct multi_match 111 | : fast_and...> 112 | {}; 113 | #endif 114 | 115 | template 116 | struct return_matches 117 | : fast_and...> 118 | { 119 | static_assert(!fast_or...>::value, 120 | "Void can't be used for returns. " 121 | "Checking for void on returns will always be false when the expression is void as well. " 122 | "Use TICK_RETURNS or has_type instead. " 123 | ); 124 | }; 125 | 126 | template 127 | struct base_traits 128 | : fast_and 129 | { 130 | typedef base_traits base_traits_type; 131 | }; 132 | 133 | template 134 | struct refine_traits 135 | { 136 | template 137 | TICK_USING(apply, base_traits<>); 138 | }; 139 | 140 | template 141 | struct refine_traits::type> 142 | { 143 | template 144 | TICK_USING_TYPENAME(apply, T::template tick_trait_base_apply); 145 | }; 146 | 147 | struct any 148 | { 149 | any() 150 | {} 151 | template 152 | any(T &&) 153 | {} 154 | }; 155 | 156 | template 157 | struct apply_refinements 158 | { 159 | typedef typename refine_traits::template apply type; 160 | }; 161 | struct evaluatable {}; 162 | 163 | #if TICK_HAS_TEMPLATE_ALIAS 164 | #define TICK_LAZY_EVAL_EXPR(...) decltype(__VA_ARGS__) 165 | #define TICK_EVAL_USING(name, ...) using name = typename __VA_ARGS__::type 166 | #else 167 | #define TICK_EVAL_USING(name, ...) struct name : tick::detail::lazy<__VA_ARGS__> {} 168 | 169 | template 170 | struct lazy 171 | : evaluatable, T 172 | {}; 173 | 174 | template 175 | struct lazy_eval 176 | : std::conditional::value, 177 | T, 178 | id 179 | >::type 180 | {}; 181 | 182 | #define TICK_LAZY_EVAL_EXPR(...) typename tick::detail::lazy_eval::type 183 | #endif 184 | 185 | template 186 | auto models_(any) -> false_type; 187 | 188 | #if TICK_LEGACY_GCC 189 | template 190 | auto models_(Trait &&) -> typename apply_refinements< 191 | TICK_LAZY_EVAL_EXPR(std::declval().template require(std::declval()...)), 192 | Trait, Ts...>::type; 193 | #else 194 | template().template require(std::declval()...))> 196 | auto models_(Trait &&) -> typename refine_traits::template apply; 197 | #endif 198 | } 199 | 200 | class ops : public tick::local_placeholders 201 | { 202 | struct private_type {}; 203 | template 204 | TICK_USING(private_enable_if, std::enable_if); 205 | 206 | template 207 | TICK_USING(has_type_, private_enable_if::value>); 208 | template 209 | TICK_USING(is_true_, private_enable_if); 210 | template 211 | TICK_USING(is_false_, private_enable_if); 212 | template 213 | TICK_USING(is_true_c_, private_enable_if); 214 | template 215 | TICK_USING(is_false_c_, private_enable_if); 216 | 217 | public: 218 | #if TICK_HAS_TEMPLATE_ALIAS 219 | template 220 | struct valid {}; 221 | #else 222 | template 223 | struct valid; 224 | template 225 | struct valid_expr 226 | : detail::evaluatable 227 | {}; 228 | template 229 | struct valid_expr, typename detail::holder< 230 | typename detail::lazy_eval::type... 231 | >::type> 232 | : detail::evaluatable 233 | { 234 | typedef valid type; 235 | }; 236 | 237 | template 238 | struct valid 239 | : valid_expr> 240 | {}; 241 | #endif 242 | 243 | template 244 | static auto returns(U &&) -> 245 | typename std::enable_if::value, int>::type; 246 | 247 | #define TICK_RETURNS(expr, ...) has_type 248 | 249 | template 250 | TICK_EVAL_USING(has_type, has_type_); 251 | 252 | template 253 | TICK_EVAL_USING(is_true, is_true_); 254 | 255 | template 256 | TICK_EVAL_USING(is_false, is_false_); 257 | 258 | template 259 | TICK_EVAL_USING(is_true_c, is_true_c_); 260 | 261 | template 262 | TICK_EVAL_USING(is_false_c, is_false_c_); 263 | 264 | 265 | // Deprecated macros 266 | #define TICK_HAS_TYPE(...) has_type 267 | #define TICK_IS_TRUE(...) is_true<__VA_ARGS__> 268 | #define TICK_IS_FALSE(...) is_false<__VA_ARGS__> 269 | #define TICK_IS_TRUE_C(...) is_true_c<(__VA_ARGS__)> 270 | #define TICK_IS_FALSE_C(...) is_false_c<(__VA_ARGS__)> 271 | 272 | 273 | template class Template> 274 | class has_template {}; 275 | 276 | template 277 | static const T& as_const(const T&); 278 | 279 | template 280 | static T& as_mutable(const T&); 281 | 282 | }; 283 | 284 | template 285 | struct refines 286 | { 287 | typedef refines tick_trait_refinements; 288 | typedef void tick_trait_base_apply_type; 289 | template 290 | struct tick_trait_base_apply 291 | : detail::base_traits::type...> 292 | { 293 | }; 294 | }; 295 | 296 | template 297 | struct base_traits_type 298 | { 299 | typedef detail::base_traits<> type; 300 | }; 301 | 302 | template 303 | struct base_traits_type::type> 306 | { 307 | typedef typename T::base_traits_type type; 308 | }; 309 | 310 | template 311 | struct models 312 | #if TICK_LEGACY_GCC 313 | : detail::id(std::declval()))>::type 314 | #else 315 | : decltype(detail::models_(std::declval())) 316 | #endif 317 | {}; 318 | 319 | template 320 | struct models 321 | { 322 | typedef Trait type; 323 | }; 324 | 325 | #ifdef _MSC_VER 326 | #define TICK_MSVC_CONSTRUCT(name) constexpr name() {} 327 | #else 328 | #define TICK_MSVC_CONSTRUCT(name) 329 | #endif 330 | 331 | #define TICK_TRAIT_REFINES(name, ...) \ 332 | struct tick_private_trait_base_ ## name : tick::ops, tick::local_quote \ 333 | { typedef tick::refines<__VA_ARGS__> type; }; \ 334 | struct tick_private_trait_ ## name; \ 335 | template \ 336 | struct name \ 337 | : tick::models \ 338 | { TICK_MSVC_CONSTRUCT(name) }; \ 339 | struct tick_private_trait_ ## name \ 340 | : tick::detail::base_requires, tick::ops, tick_private_trait_base_ ## name::type 341 | 342 | #define TICK_TRAIT(...) \ 343 | TICK_PP_EXPAND( \ 344 | TICK_TRAIT_REFINES TICK_IIF(TICK_PP_ARGS_IS_SINGLE(__VA_ARGS__)) \ 345 | ( \ 346 | (__VA_ARGS__,), \ 347 | (__VA_ARGS__)) \ 348 | ) 349 | 350 | // Add support for zlang 351 | #define ZLANG_tick_trait (TICK_TRAIT) 352 | 353 | } 354 | 355 | #endif 356 | -------------------------------------------------------------------------------- /tick/detail/fold.h: -------------------------------------------------------------------------------- 1 | /*============================================================================= 2 | Copyright (c) 2014 Paul Fultz II 3 | fold.h 4 | Distributed under the Boost Software License, Version 1.0. (See accompanying 5 | file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | ==============================================================================*/ 7 | 8 | #ifndef TICK_GUARD_FOLD_H 9 | #define TICK_GUARD_FOLD_H 10 | 11 | namespace tick { namespace detail { 12 | 13 | template struct fold_impl 14 | { 15 | template