├── .gitignore ├── LICENSE ├── README.md ├── demo.cpp └── parameter2.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # parameter2 2 | Modern version of boost.parameter enabling named parameters without macros and better compile time. 3 | *it should be noted that this lib is in a very early stage and should not be used for anything but fun. Input is however very much appreciated* 4 | 5 | In order to use named parameters the user must first define the names names. Names are defined a global constexpr variables which wrap compile time accessable parameters. Each name needs a number in order to disambiguate between two names which would otherwise have the same type. Numbers need not be in asscending order or contiguous but must be unique within a call to `make_tuple`. Names also take an "acceptance policy" in other words a metafunction which returns true or false depending on whether the type provided is adiquate. In the `parameter2` namespace there are handy `is` and `convertible` aliases which create such a metafunction. The third and optional proameters is the default value policy. Default values are used if the users does not provide a parameter. Both compile time knoen and runtime known defaults can be passed. 6 | 7 | ```C++ 8 | namespace p2 = parameter2; 9 | //we can capture default value as a constexpr and deduce the type. The 'convertible' metafunction will be used 10 | constexpr auto length = p2::make_tag<1>(4); 11 | 12 | //we can also use "wrapped" default values as long as they are convertible 13 | constexpr p2::tag<2, p2::convertible, std::integral_constant> height{}; 14 | 15 | struct DepthMaker 16 | { 17 | int operator()() { 18 | return 42; 19 | } 20 | }; 21 | 22 | //if all else fails we can specify a functor which makes our default value 23 | constexpr p2::tag<3, p2::is, DepthMaker> depth{}; 24 | 25 | template 26 | struct is_magic_thing : false_type{}; 27 | template 28 | struct is_magic_thing> : true_type{}; 29 | 30 | //we could also use our own metafunction to test if the parameter is suitable 31 | //metafunctions passed must fullfill brigand lambda syntax 32 | constexpr p2::tag<3, is_magic_thing, magic_maker> magic{}; 33 | 34 | 35 | template 36 | void draw(Ts&&...args) { 37 | //make tuple uses D style syntax, compile time values as first arg list and runtime in the second arg list 38 | //first arg list must contain all name tags in the desired positional order 39 | //second list must be the args passed by the user 40 | auto ta = p2::make_tuple(length, height, depth)(std::forward(args)...); 41 | auto h = ta[height]; //input parameter indexing is trivial 42 | auto &l = ta[length]; 43 | doSomething(l); 44 | doSomething(ta[length]); //indexing is resolved at compile time so this is not as inefficient as it looks 45 | } 46 | 47 | int main(int argc, const char** argv) 48 | { 49 | draw(length = 1, height = 8); 50 | } 51 | ``` 52 | 53 | In our opinion Boost.parameter is slightly too premissive when it comes to convertability, parameter2 follows the following strict rules: 54 | - all positional arguements must be alligned left of one or zero named arguements. If a named arguement is provided all arguements to its right must be named or uniquly convertible. 55 | - deduced parameters are only allowed if they are convertible to exactly one candidate. 56 | 57 | ## goals: 58 | - at least 10x faster compile time 59 | - make implementing a function which takes named parameters much easier 60 | - don't use macros (we hate them) 61 | - allow return type to be dependant on input types (allows boost.hana style coding) 62 | - no `#define BOOST_PARAMETER_MAX_ARITY` and other hackery 63 | 64 | ## non goals: 65 | - no support for named template parameters (implementation is trivial and boost.hana style will make this obsolete in the long run) 66 | 67 | ## open questions: 68 | - should we force users to wrap out parameters with 'std::ref'? (out parameters should be getting more and more unpopular due to compiler improvements and their related coding style improvments. Also chances are that if a user wants the added clairity of named parameters that they also want to visibly state the a parameter is an out parameter.) 69 | - should we support the capture default values as a constexpr parameter? (the compiler should be able eliminate any unneeded overhead, however in the embedded domain the size of debug builds also matter.) 70 | - should we support non constexpr defaults? This is really only critical if we want to default out parameters. 71 | 72 | ## requirements: 73 | - c++14 or higher compiler 74 | - since our goal is speed we use brigand (the only dependancy), however use with any other MPL library possible to support if needed 75 | -------------------------------------------------------------------------------- /demo.cpp: -------------------------------------------------------------------------------- 1 | #include "parameter2.hpp" 2 | 3 | namespace p2 = parameter2; 4 | struct DepthMaker 5 | { 6 | int operator()() { 7 | return 42; 8 | } 9 | }; 10 | constexpr auto length = p2::make_tag<1>(4); //we can capture default value as a constexpr 11 | constexpr p2::tag<2, int, std::integral_constant> height{}; //we can also use "wrapped" default values as long as they are convertable 12 | constexpr p2::tag<3, int, DepthMaker> depth{}; //if all else fails we can specify a functor which makes our default value 13 | 14 | 15 | template 16 | void draw(Ts&&...args) { 17 | //make tuple uses D style syntax, compile time values as first arg list and runtime in the second arg list 18 | //first arg list must contain all name tags in the desired positional order 19 | //second list must be the args passed by the user 20 | auto ta = p2::make_tuple(length, height, depth)(std::forward(args)...); 21 | auto l = ta[height]; //input parameter indexing is trivial 22 | } 23 | 24 | int main(int argc, const char** argv) 25 | { 26 | draw(length = 1, height = 8); 27 | } -------------------------------------------------------------------------------- /parameter2.hpp: -------------------------------------------------------------------------------- 1 | /*================================================================================================== 2 | Copyright (c) 2016 Odin Holmes and Carlos van Rooijen 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 5 | =================================================================================================**/ 6 | 7 | #pragma once 8 | #define BRIGAND_NO_BOOST_SUPPORT 9 | #include "brigand\brigand.hpp" 10 | 11 | 12 | namespace parameter2 { 13 | template 14 | struct tag; 15 | namespace detail { 16 | template 17 | struct make_default_value { 18 | T operator()() { 19 | return{}; 20 | } 21 | }; 22 | struct use_constexpr_value {}; 23 | ///index is the arguements position, use for disambiguation of types 24 | ///T is the parameter type, must be copy or move constructable 25 | ///DefaultValueMaker is a functor which returns the default value 26 | template 27 | struct tagged_parameter { 28 | using parameter_type = T; 29 | T val_; 30 | }; 31 | 32 | template 33 | struct make_default; 34 | template 35 | struct make_default> { 36 | template 37 | auto operator()(const D& defaults) { 38 | return DefaultValueMaker{}(); 39 | } 40 | }; 41 | template 42 | struct make_default> { 43 | template 44 | T operator()(const D& defaults) { 45 | return std::get, tag>::value>(defaults).default_; 46 | } 47 | }; 48 | 49 | template 50 | struct make_default>> { 51 | template 52 | T operator()(const D& ) { 53 | return V; 54 | } 55 | }; 56 | 57 | template 58 | struct make_defaults; 59 | template 60 | struct make_defaults>{ 61 | template 62 | std::tuple operator()(const D& defaults) { 63 | return std::tuple{ make_default{}(defaults)... }; 64 | } 65 | }; 66 | 67 | template 68 | struct get_value { 69 | using type = typename T::parameter_type; 70 | }; 71 | 72 | template 73 | struct results_in_one_of { 74 | using type = brigand::any, std::is_same>; 75 | }; 76 | 77 | template 78 | struct not_results_in_one_of { 79 | using type = brigand::none, std::is_same>; 80 | }; 81 | 82 | template 83 | struct is_reference_wrapper : std::false_type {}; 84 | template 85 | struct is_reference_wrapper> : std::true_type {}; 86 | 87 | template 88 | struct is_tag : std::false_type {}; 89 | template 90 | struct is_tag> : std::true_type {}; 91 | 92 | //PL is a list of taks for which we have parameters 93 | //DL is a list of tags from which we need the defaults 94 | template 95 | struct parameter_tuple { 96 | using parameter_types = brigand::list; 97 | using default_types = brigand::transform>; 98 | brigand::wrap parameters; 99 | brigand::wrap defaults; 100 | //if we have a parameter 101 | template 102 | std::enable_if_t< 103 | (brigand::contains, T>::value && 104 | (!is_reference_wrapper::value)), 105 | typename T::parameter_type 106 | >& operator[](T) { 107 | return std::get::value>(parameters); 108 | } 109 | //if we have a parameter and a the type is a ref wraper 110 | template 111 | std::enable_if_t< 112 | (brigand::contains, T>::value && 113 | is_reference_wrapper::value), 114 | typename T::parameter_type::type 115 | >& operator[](T) { 116 | return std::get::value>(parameters).get(); 117 | } 118 | //if we do not have the parameter use default 119 | template 120 | std::enable_if_t,T>::value, typename T::parameter_type>& operator[](T) { 121 | return std::get::value>(defaults); 122 | } 123 | }; 124 | 125 | 126 | template 127 | struct tuple_maker { 128 | std::tuple defaults; 129 | template 130 | auto operator()(Ts...args) { 131 | using all_tags = brigand::list; 132 | using defaults_needed = brigand::remove_if>; 133 | using tags_with_parameters = brigand::remove_if>; 134 | constexpr bool allArguementsNamed = brigand::all < tags_with_parameters, is_tag>::value; 135 | constexpr bool noArguementIsNamed = brigand::none < tags_with_parameters, is_tag>::value; 136 | constexpr bool allNotProvidedArguementsHaveDefaults = brigand::none < defaults_needed, std::is_same>::value; 137 | static_assert(allNotProvidedArguementsHaveDefaults, ""); 138 | static_assert(allArguementsNamed, ""); 139 | return parameter_tuple{ std::tuple{args.val_...}, make_defaults{}(defaults) }; 140 | } 141 | }; 142 | } 143 | 144 | ///index is the arguements position, use for disambiguation of types 145 | ///T is the parameter type, must be copy or move constructable 146 | ///DefaultValueMaker is a functor which returns the default value 147 | template> 148 | struct tag { 149 | using tagged_parameter_type = detail::tagged_parameter; 150 | using parameter_type = T; 151 | constexpr tagged_parameter_type operator=(T in) const { 152 | return{ std::move(in) }; 153 | } 154 | 155 | }; 156 | 157 | template 158 | struct tag { 159 | T default_; 160 | using parameter_type = T; 161 | using tagged_parameter_type = detail::tagged_parameter; 162 | constexpr tagged_parameter_type operator=(T in) const { 163 | return{ std::move(in) }; 164 | } 165 | }; 166 | 167 | 168 | template 169 | constexpr tag make_tag(T t) { 170 | return{ t }; 171 | } 172 | 173 | template 174 | constexpr detail::tuple_maker make_tuple(const Ts...args) { 175 | return{ std::tuple{args...} }; 176 | } 177 | } 178 | 179 | 180 | --------------------------------------------------------------------------------