What if there were an additional parameter list allowed for defining custom literals, specifically:
template< typename ...Args > <return_type> operator ""_<suffix> ( Args &&... ) { /*...*/ }
This syntax for invoking this literal operator would use an aggregate-initialization block, such as would be used to initialize a struct. So for example, this could be used to define a terse suffix for std::tuple:
template< typename ...Args > auto operator ""_tuple ( Args &&...args ) {
return tuple( std::forward<Args>( args )... ); // Relies on new class template argument deduction from C++17
}
// ...
auto tup = { 1.0f, "unnamed", '\n' }_tuple;
I realize that this particular example might not be particularly motivating, since we already have std::make_tuple, and the new class template arg deduction feature alongside that means that both give nice terse syntax for creating a tuple. I use it here mostly because it provides a straightforward way to express the idea. Another example could offer a natural ordered-pair-like syntax for a custom linear algebra Vector class:
template< typename T, size_t N >
struct Vector : std::array<T, N> {
// ...
};
template< typename T, typename S, size_t N >
Scalar dot( Vector<T, N> const &v1, Vector<S, N> const &v2 ) {
// compute and return dot product of v1 and v2...
}
template< typename ...Args > auto operator ""_v ( Args &&...args ) {
return Vector<std::common_type_t<Args...>, sizeof...(Args)>{ std::forward<Args>( args )... };
}
// ...
auto vec3f = {0.74f, 0.74f, 0.0f}_v;
float s = dot( vec3f, {1.0f, 0.0f, 0.0f}_v );
Of course, the above could be achieved with the currently permissible 'char *' parameter for custom literal operators, but that would require some tricky compile-time parsing of the char * string to determine the Vector's template arguments T and N, as well as other compile-time parsing, and the resulting syntax doesn't seem quite as natural or as close to the common mathematics notation for ordered pairs:
auto vec3f = "0.74f, 0.74f, 0.0f"_v;
float s = dot( vec3f, "1.0f, 0.0f, 0.0f"_v );
I also realize the above could also be achieved using normal template functions or 'make_vector" functions, and in a pinch if terseness is desired the make_ functions could just be given very short names. But pointing that out would serve as an argument against custom literal operators in general, not only this specific extension to them.
Another objection I could anticipate is if this could maybe be seen as another gateway towards the objection compiler implementors have had against the proposed compile-time string literals which return each string character as a separate 'char' non-type template argument, namely that of encouraging the use of too many template arguments which can slow compilation. But at least for that specific use case I don't see this likely to lead to the same result; it wouldn't make constructing such templates any more convenient than it is presently, since it would still require listing separate characters separately:
auto constexpr s = {'s', 't', 'r', 'i', 'n', 'g', '\0'}_string_literal;
So, does this seem to others like a useful extension to the custom user literals mechanism? I personally quite like, in the Vector example, how it would enable a notation quite close to traditional math notations. It could make life easier for any custom type that is convenient to express tersely as some ordered heterogeneous tuple: the compiler would provide type checking and automatic separation of the different arguments without requiring compile-time string parsing.
-Andy