4.6.0
Freundlich's C++ toolkit
Loading...
Searching...
No Matches
fcppt.literal

Description

Literals or polymorphic integer constants.

Motivation

In C++, most literals are polymorphic in a sense that they can be implicitly converted to different types. For example, 0 can be used in places where nullptr can or to initialize a float to 0.f. Using literals like this, however, doesn't work to initialize integer-like types with explicit constructors or types that require special factory functions. This can quickly become a problem in generic code. Consider a generic function that tries to divide its argument by two.

template <typename T>
T half(T const _value)
{
return _value / 2;
}

A lot of types provide an operator/ but they can't be implicitly converted from literals, for example strong typedefs.

void try_strong()
{
// Doesn't work
// half(strong_int(10));
}

Specializing literals

The code above obviously doesn't work, so you might conclude from this example that we should change the function half to say T{2} instead of 2. However, other types like units without quantities in Boost.Units can only be initialized by a special factory function. Therefore, fcppt provides a customization point which is used to create objects from literals. For example, we could have found the following type inside a library:

namespace mine
{
class custom_type
{
public:
static custom_type make(int const _value) { return custom_type{_value}; }
[[nodiscard]] int get() const { return this->value_; }
private:
explicit custom_type(int const _value) : value_{_value} {}
int value_;
};
inline custom_type operator/(custom_type const _left, custom_type const _right)
{
return custom_type::make(_left.get() / _right.get());
}
}
}

To make fcppt::literal work with this type, we need to provide a specialization for fcppt::make_literal.

namespace fcppt
{
template <>
struct make_literal<mine::custom_type>
{
using decorated_type = mine::custom_type;
template <typename Fundamental>
static mine::custom_type get(Fundamental const _value)
{
static_assert(
std::is_same_v<Fundamental, int>, "custom_types should be initialized by integers");
return mine::custom_type::make(_value);
}
};
}

Using literals

In order to make the half function work, we call fcppt::literal.

template <typename T>
T half_2(T const _value)
{
return _value / fcppt::literal<T>(2);
}

We can then call our half_2 function with custom_type

void literal_use()
{
// Prints 2
std::cout << half_2(mine::custom_type::make(4)).get() << '\n';
}
Note
As a general rule of thumb, you should only use literals of type int with fcppt::literal but this isn't enforced by the type system because it might be too restrictive.

Classes

struct  fcppt::make_literal< Type, Enable >
 
struct  fcppt::make_literal< fcppt::strong_typedef< Type, Tag > >
 

Functions

template<typename Type , typename Arg >
constexpr fcppt::make_literal< Type >::decorated_type fcppt::literal (Arg const &&_integral) noexcept
 Creates a literal of a type.
 

Function Documentation

◆ literal()

template<typename Type , typename Arg >
fcppt::make_literal< Type >::decorated_type fcppt::literal ( Arg const && _integral)
constexprnoexcept

Creates a literal of a type.

Creates a literal of type Type from the value _integral, using fcppt::make_literal to do any conversions if necessary.

Template Parameters
TypeThe literal type to create. Must be a value type. See fcppt::type_traits::is_value.
ArgAn arithmetic type.