**Document number**: P0827R0 **Date**: 2017-10-16 **Reply-to**: John McFarlane, [cnl@john.mcfarlane.name](mailto:cnl@john.mcfarlane.name) **Reply-to**: Louis Dionne, [ldionne.2@gmail.com](mailto:ldionne.2@gmail.com) **Audience**: SG6, SG14, LEWG # General-Purpose Constant Value Type ## Introduction A constant value type can make some arithmetic operations more efficient. For example, some low-level operations using the fixed-point type in [[P0037](http://wg21.link/p0037)] effectively become no-ops: ```c++ auto a = fixed_point{1}; // fixed-point wrapper around an int with resolution 2^-10 auto b = a << 1; // fixed_point{2}, requires a run-time shift operation auto c = a << integral_constant{}; // fixed_point{2}, bitwise equal to a; only the type has changed ``` Combined with a user-defined literal, this code can be made almost as terse and readable as the run-time code: ```c++ auto d = a << 1static; ``` Many other examples exists of situations where the value of an argument might affect the type of a result: ```c++ // snug returns the narrowest type that can hold the given value auto e = snug(100); // sizeof(e) == sizeof(int), snug cannot determine type from value auto f = snug(100static); // sizeof(f) == sizeof(int8_t), but it can determine type from type ``` This feature would also interact well with class template argument deduction: ```c++ auto g = fixed_point(0x100); // fixed_point{256}, type cannot be determined based on initial value auto h = fixed_point(0x100static); // fixed_point{256}, 8 fewer bits are devoted to low-order bits ``` Currently, the only standard type for expressing a constant value types is `integral_constant` which has drawbacks: 1. It requires that two template parameters be specified where `template` would mean only one was necessary. 2. If future revisions to the standard relax restrictions on non-type template parameters, it will be ill-named and ill-prepared. 3. A lack of operator overloads means that results of many operations are values, e.g.: ```c++ auto g = integral_constant{} + integral_constant{}; // result is 4, not integral_constant{} ``` We propose a replacement for `integral_constant` called `constant` and an accompanying user-defined literal which address the above issues. ## Prior Art A similar proposal to improve on `integral_constant` was made in [P0377](http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0377r0.html). It addresses the first of the three drawbacks listed above: namely eliminating `integral_constant`'s type template parameter. But it does not address the other two. User-defined literals returning an constant value type can be found in multiple libraries and on forums including in [[Boost.Hana](http://www.boost.org/doc/libs/1_61_0/libs/hana/doc/html/structboost_1_1hana_1_1integral__constant.html#a1c078fd00db48686ca9e0aa17f47344e)] and [[CNL](https://github.com/johnmcfarlane/cnl/blob/develop/include/cnl/integral_constant.h#L100)]. ## Details ### Definition of `constant` ```c++ template struct constant { using value_type = decltype(Value); static constexpr value_type value = Value; constexpr operator value_type() const { return value; } }; ``` The implicit conversion operator ensures that `constant` objects are as easy to use as the variable they mimic. In the following example, the result of `!=` is `constant` which is then implicitly converted to `bool`: ```c++ static_assert(constant<1>{} != constant<2>{}); ``` ### Operator Overloads A complete set of unary and binary operators ensure that operations taking only `constant` operands do not return non-`constant` results: ```c++ // unary operator @ template constexpr auto operator@(constant rhs) noexcept { return constant<@ Value1>{}; } // binary operator @ template constexpr auto operator@(constant lhs, constant rhs) noexcept { return constant{}; } ``` ### User-Defined Literals A user-defined literal returns `constant` objects of values of type, `maxint_t`. ```c++ namespace literals { template constexpr auto operator ""static() noexcept; } ``` (Suffix, `static`, is by no means final. Unfortunately, preferred suffix, `c`, is not suitable for combination with hexadecimal literals.) The input string could contain whole numbers in a variety of bases: ```c++ using namespace literals; auto i = 1000000000000static; // constant<1000000000000LL> auto j = 0x401static; // constant<1025LL> auto k = 0b10000static; // constant<16LL> auto l = 077static; // constant<63LL> ``` ## Discussion The use of a pack of `char` as input to `operator ""static` is limiting. However, there is currently no better alternative. Future language revisions may allow some improvements: * fractional values, e.g. with a decimal place; * non-string input and * greater range than `intmax_t`. Care should be taken to ensure the current design does not preclude these possibilities. ## Reference Implementation A simple proof of concept is available on [[CompilerExplorer](https://godbolt.org/g/vXpEmX)].