TDDD38 - Extra lecture User-defined literals Eric Elfving

advertisement
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
Download