TDDD38 - Extra lecture User-defined literals Eric Elfving Department of Computer and Information Science Linköping University 1 / 11 Definition Allows integer, floating-point, character, and string literals to produce objects of user-defined type by defining a user-defined suffix. cppreference.com Allows the user to explicitly write values of their own types as literals in code. 2 / 11 Examples constexpr long double operator"" _deg ( long double deg ) { return deg*3.141592/180; } ... auto radians = 90_deg; string operator"" _s ( char const * s, size_t n ) { return string(s, n); } ... auto str = "a simple string"_s; 3 / 11 • Always named operator"" _<your name>. The underscore is mandatory for names not declared in the standard. • Can take several types 1 , but usally overloaded for these: • • • (unsigned long long) (long double) (const char *, size_t) • Default arguments are not allowed! 1 See http: //en.cppreference.com/w/cpp/language/user_literal for all 4 / 11 Predifined in the STL There is an inline namespace std::literals declared over several header files: • <chrono> has several user-defined literals defined in std::literals::chrono_literals (all overloaded both for long long and long double): Function Return type operator""h duration representing hours operator""min duration representing minutes operator""s duration representing seconds (also ms, us, ns for milliseconds, microseconds and nanoseconds) 5 / 11 • <string> declares operator""s(const char*, size_t) (in std::literals::string_literals to create a std::string-literal auto s = "my string"s; static_assert(is_same<decltype(s), string>::value, ""); // C++11 static_assert(is_same_v<decltype(s), string>); // C++17 6 / 11 • <complex> defines literals for imaginary numbers in std::literals::complex_literals. These are named i, il and if for the types double, long double and float. auto c = 3.5 + 5i; 7 / 11 There is one problem with user defined literals. Even though the value is sent from a literal (constant value), the parameter is not regarded as a constant expression in the function. 8 / 11 bool operator"" _test(const unsigned long long t) { static_assert(t == 5, ""); ... } Listing 1: GCC (6.0) error: non-constant condition for static assertion static_assert(t == 5, ""); ^ error: 't' is not a constant expression Listing 2: Clang (3.8) error: static_assert expression is not an integral constant expression static_assert(t == 5, ""); ^~~~~~ 9 / 11 Variadic templates to the rescue! 10 / 11 We create a template class taking an argument pack to parse several characters to an integer value. using ULL = unsigned long long; template<ULL Sum, char... Chars> struct parse; template <ULL Sum, char Head, char... Tail> struct parse<Sum, Head, Tail...> { const static ULL value = parse<Sum*10 + (Head - '0'), Tail...>::value; }; template <ULL Sum> struct parse<Sum> { const static ULL value = Sum; }; 11 / 11 Then we change our function: template<char ...Chars> bool operator"" _test() { static_assert(parse<0, Chars...>::value == 5, ""); ... } ... bool b = 5_test; bool b2 = 15_test; Listing 3: Clang error: static_assert failed "" static_assert(parse<0, Chars...>::value == 5, ""); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ note: in instantiation of function template specialization 'operator "" _test<'1', '5'>' requested here bool b2 = 15_test; ^ www.liu.se