String literal with dependent type — impossible? - c++

Is it possible to define a user-defined string literal conversion operator such that the type of its result depends on the value of its string input?
It is easy with user-defined integer and floating point literals because they admit literal operator templates, and the actual characters of the literal are passed to it as template arguments. Example:
template <char... s> struct silly { using type = int; };
template <char... s> struct silly<'1', s...> { using type = double; };
template <char... s>
typename silly<s...>::type operator"" _silly() { return 0; }
static_assert(std::is_same<int, decltype(4321_silly)>::value, "no luck");
static_assert(std::is_same<double, decltype(1234_silly)>::value, "no luck");
No such thing seems to exist for user-defined string literals.
Is there perhaps another way to do this, either in the current standard or planned/discussed for some future revision?

No, not possible, outside of serious macro hackery. String literals are accessed via constexpr, and return type of constexpr cannot depend on values of arguments.
The proposed <char...> operator"" for string literals ran into issues with "raw or processed" issues and how to specify it, and where dropped because hashing out those issues in time for the next standard would be hard, and/or ROI would be low. (at least from my casual reading of what happened).
I do not know if it died on the vine, or is still being worked on.
The hackery would be to pass <arr[0], arr[1], arr[2]> to a template pseduo-manually, and would not (directly) involve user defined literal syntax. It has many issues.

Related

C++20 concept matching string literal

In C++20 it is possible to write a wrapper class1 which only accepts string literals.
struct string_literal
{
template<size_t N>
consteval string_literal(char const (&s)[N]) : p(s) {}
char const* p;
};
void takes_literal(string_literal lit) {
// use lit.p here
}
Is it also possible to write a concept that only matches string literals?
1 This was the original question, but per the comments and answers here: the premise is flawed: it seems that this construct does not, in fact, accept only string literals.
A char const* which points into a string literal is virtually no different from any other char const*. The fact that a literal starts its life as an array is irrelevant, as non-literal character arrays can also be created. To my knowledge, there is exactly one difference: pointers to string literals cannot be used as non-type template parameters.
That's not particularly helpful. Even if we were restricted to compile-time code execution, you can get non-literal char const*s which also cannot be used as NTTPs (by creating a std::string, which can now be done at compile-time. You can call constexpr functions on string::c_strs pointer, but you can't use the result as an NTTP).
The best you can do is to create a user-defined literal operator that returns your string_literal object. You can make it so that only this literal operator can construct such a type (besides copying, of course). But even then, they can call your operator"" directly with a non-literal, and there is nothing you can do about it.
Instead, you should re-evaluate why you need to know if it is a string literal specifically.
Whereas const char(&)[N] isn't necessary a string literal, you might create concept to match const char(&)[N]:
template <typename T>
struct is_str_literal_impl : std::false_type{};
template <std::size_t N>
struct is_str_literal_impl<const char[N]> : std::true_type{};
template <typename T>
concept concept_str_literal = is_str_literal_impl<T>::value;
void takes_literal(concept_str_literal auto& lit) {
// use lit.p here
}
Demo

understanding user defined string literals addition for c++20

I found in user defined string literal the following:
For user-defined string literals, let str be the literal without ud-suffix:
a) If the overload set includes a string literal operator template with a non-type template parameter for which str is a well-formed template argument, then the user-defined literal expression is treated as a function call operator "" X<str>(),
That sounds a bit mysterious to me. Can some one give an example how this can be used?
The following did not work at all and I can't catch the point what the non type template parameter for MyType can be. It seems not a char* nor const char*:
template < ??? >
struct MyType
{
const char* c;
constexpr MyType( const char* in ): c{in}{}
};
template < MyType t > auto operator ""_y() { return t; }
int main()
{
"Check it"_y;
}
This is confusing wording, which was copied directly from the standard:
If [the overload set] contains a literal operator template with a non-type template parameter for which str is a well-formed template-argument
The confusing bit is the question of what "for which str is a well-formed template argument" specifically applies to. A direct reading of the passage from the standard suggests that "for which" refers to the "non-type template parameter", since that is the text directly preceding the words "for which". However, if you look at how the standard says the function will be invoked, you see this:
operator "" X<str>()
str is being passed to the operator, which the implication being that an implicit conversion will take place between str and the "non-type template parameter". That is, str is a valid "template argument" of the overloaded function, not of the template parameter of the overloaded function. And thus, the "for which" part should refer to the "literal operator template with a non-type template parameter", not the "non-type template parameter".
That having been said, to make your code work, you need to do more than to just remove the template argument from MyType.
You might have noticed a certain oddity in C++ surrounding non-type template parameters (NTTP). For example, NTTPs have always been able to be pointers to things. But you could never do this:
template<const char *literal> void foo() {}
foo<"literal">();
The standard expressly forbids a pointer NTTP from being initialized with a string literal. And C++20 does not change this.
Therefore, you can't take a pointer. You have to take what the literal actually is: an array. But you can't make your code work by taking const char (&in)[] as a parameter either. A literal is not an unsized array (since an "unsized array" is not a real object type). That array parameter must be sized appropriately to the literal.
Which means that you must deduce the size from a size template parameter.
Also, other rules flat-out forbid you from ever storing a pointer to a string literal in an NTTP (directly or indirectly). So, if you want a type that represents an entire string literal in an NTTP, that NTTP type must contain an array that is sized to that size.
So the simplest, functional string literal NTTP you could build would be:
template<size_t N>
struct string_literal
{
std::array<char, N> arr_;
constexpr string_literal(const char(&in)[N]) : arr_{}
{
std::copy(in, in + N, arr_.begin());
}
};
And thanks to CTAD, you can just use template < string_literal t > auto operator ""_y() to define your UDL.
Note that this string_literal class explicitly includes the NUL terminator as part of the array.

Default fallback overload of a function template

Short general question:
Is there a way to provide a default "fallback" overload of a function template? I read about some techniques here on Stack Overflow, but one requires using a variadic function (f(...)) which has some serious drawbacks in my case, and other requires listing all the type combinations that are overloaded, which is too verbose and not automated enough for my needs. This question was asked, but it's a few years old now, so I was wondering if there are some new solutions to this using the features of the latest standards and maybe even some solutions that will be possible in C++20 using concepts.
Long detailed question:
I'm trying to implement something like dynamic typing in C++. The point is, that I have several "abstract" types like Bool, Integer, Decimal, String etc. that are represented with some built-in types i.e. Integer is stored as a long long, but any integral type except bool is converted to it.
Now I started to implement operators. I could implement every possible overload (i.e. Bool + Integer, Integer + Integer, ...) manually, but I'd like to have only one implementation per some "category" i.e. Decimal + any_lower_type_than<Decimal> (commutative), where any_lower_type_than<Integer> refers to certain hierarchy of the abstract types. I have all the needed metafunctions to distinguish the categories and hierarchy implemented. I then use SFINAE with those metafunctions to provide the definitions. For example:
// decimal + lower, commutative:
template <typename first_t, typename second_t,
std::enable_if_t<commutative_with_lower<first_t, second_t, Decimal>::value>* = nullptr>
Decimal operator+ (const first_t& first, const second_t& second) {
return first + second;
}
// string * lower than integer, commutative:
template <typename first_t, typename second_t,
std::enable_if_t<commutative_with_lower_than<first_t, second_t, String, Integer>::value>* = nullptr>
String operator* (const first_t& first, const second_t& second) {
String string_arg = is_string<first_t>::value ? first : second;
auto other_arg = is_string<first_t>::value ? second : first;
String result = "";
for (decltype(other_arg) i = 0; i < other_arg; ++i)
result += string_arg;
return result;
}
So that's all OK, but what I need now is some default "fallback" implementation, that gets called as a last resort, when no match was found. So I need to somehow force the fallback implementation to be the worst possible match, but at the same time be a match for any case.
I read about the variadic function "sinkhole" being a worse match than anything. So the natural approach would be to provide the fallback as operator+ (...), which is impossible of course. So I changed all the operators to regular functions e.g. operator_add and then implemented the operator+ itself at a higher level by calling the appropriate operator_add overload, where the default overload is implemented as a variadic function operator_add(...). But then I encountered another problem. Variadic functions accept only trivial types. But I need to use this technique for user-defined types as well.
So the question is: Is there any alternative technique to the variadic function sinkhole that would ensure the worst possible match? Is there maybe even a way to do this without modifying the functional arguments, maybe by modifying the template arguments, so that I could use the technique on actual operators, that have fixed functional arguments signature?
Add another parameter to your operator_adds, including the fallback.
Give the fallback's extra parameter a different type (say, long), than the rest (say, int).
Make your operator+ call it with an int argument so that the fallback has a worse conversion.
So the question is: Is there any alternative technique to the variadic function sinkhole that would ensure the worst possible match?
You might use hierarchy to order overloads:
template <std::size_t N> struct overloadPriority : overloadPriority<N -1> {};
template <> struct overloadPriority<0>{};
then
template <typename T>
std::enable_if_t<MyTrait5<T>::value> foo_impl(T&&, overloadPriority<5>) {/*..*/}
template <typename T>
std::enable_if_t<MyTrait4<T>::value> foo_impl(T&&, overloadPriority<4>) {/*..*/}
// ...
template <typename T>
void foo_impl(T&&, overloadPriority<0>) {/*..*/} // Fallback
template <typename T>
auto foo(T&& t)
{
return foo_impl(std::forward<T>(t), overloadPriority<42>{});
// number greater or equal to max overload_priority used by that overload.
}
You could simply define your fallback to have a trailing parameter pack:
template <typename A, typename B, typename... T>
whatever_t operator_add(A&& a, B&& b, T...)
{
…
}
Overloading will always prefer non-templates over templates and prefer a more specialized template to a less specialized template. Based on [temp.deduct.partial]/11, if two function templates are otherwise equally well-suited the one with a trailing parameter pack loses.
The only downside of this approach is that there will be potential issues should you ever plan to add overloads of operator_add() that take more than two arguments. Also, should someone accidentally pass more than two arguments, the fallback would be called and just swallow them. Unfortunately, due to the issue mentioned in the comments by Jarod42, we cannot simply use std::enable_if to remove the overload in case there actually happen to be arguments for the parameter pack (like I originally proposed). One thing you could do to at least guard against the accidental call is just add another overload that would be called in this case and define it as deleted:
template <typename A, typename B, typename C, typename... T>
void operator_add(A&&, B&&, C&&, T...) = delete;

How does this implementation of std::is_class work?

I'm trying to understand the implementation of std::is_class. I've copied some possible implementations and compiled them, hoping to figure out how they work. That done, I find that all the computations are done during compilation (as I should have figured out sooner, looking back), so gdb can give me no more detail on what exactly is going on.
The implementation I'm struggling to understand is this one:
template<class T, T v>
struct integral_constant{
static constexpr T value = v;
typedef T value_type;
typedef integral_constant type;
constexpr operator value_type() const noexcept {
return value;
}
};
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
//Not concerned about the is_union<T> implementation right now
template <class T>
struct is_class : std::integral_constant<bool, sizeof(detail::test<T>(0))==1
&& !std::is_union<T>::value> {};
I'm having trouble with the two commented lines. This first line:
template<class T> char test(int T::*);
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The second line I want to understand is:
template<class T> two test(...);
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context? I thought an ellipsis as a function argument required one defined argument before the ...?
I would like to understand what this code is doing. I know I can just use the already implemented functions from the standard library, but I want to understand how they work.
References:
std::is_class
std::integral_constant
What you are looking at is some programming technologie called "SFINAE" which stands for "Substitution failure is not an error". The basic idea is this:
namespace detail {
template <class T> char test(int T::*); //this line
struct two{
char c[2];
};
template <class T> two test(...); //this line
}
This namespace provides 2 overloads for test(). Both are templates, resolved at compile time. The first one takes a int T::* as argument. It is called a Member-Pointer and is a pointer to an int, but to an int thats a member of the class T. This is only a valid expression, if T is a class.
The second one is taking any number of arguments, which is valid in any case.
So how is it used?
sizeof(detail::test<T>(0))==1
Ok, we pass the function a 0 - this can be a pointer and especially a member-pointer - no information gained which overload to use from this.
So if T is a class, then we could use both the T::* and the ... overload here - and since the T::* overload is the more specific one here, it is used.
But if T is not a class, then we cant have something like T::* and the overload is ill-formed. But its a failure that happened during template-parameter substitution. And since "substitution failures are not an error" the compiler will silently ignore this overload.
Afterwards is the sizeof() applied. Noticed the different return types? So depending on T the compiler chooses the right overload and therefore the right return type, resulting in a size of either sizeof(char) or sizeof(char[2]).
And finally, since we only use the size of this function and never actually call it, we dont need an implementation.
Part of what is confusing you, which isn't explained by the other answers so far, is that the test functions are never actually called. The fact they have no definitions doesn't matter if you don't call them. As you realised, the whole thing happens at compile time, without running any code.
The expression sizeof(detail::test<T>(0)) uses the sizeof operator on a function call expression. The operand of sizeof is an unevaluated context, which means that the compiler doesn't actually execute that code (i.e. evaluate it to determine the result). It isn't necessary to call that function in order to know the sizeof what the result would be if you called it. To know the size of the result the compiler only needs to see the declarations of the various test functions (to know their return types) and then to perform overload resolution to see which one would be called, and so to find what the sizeof the result would be.
The rest of the puzzle is that the unevaluated function call detail::test<T>(0) determines whether T can be used to form a pointer-to-member type int T::*, which is only possible if T is a class type (because non-classes can't have members, and so can't have pointers to their members). If T is a class then the first test overload can be called, otherwise the second overload gets called. The second overload uses a printf-style ... parameter list, meaning it accepts anything, but is also considered a worse match than any other viable function (otherwise functions using ... would be too "greedy" and get called all the time, even if there's a more specific function t hat matches the arguments exactly). In this code the ... function is a fallback for "if nothing else matches, call this function", so if T isn't a class type the fallback is used.
It doesn't matter if the class type really has a member variable of type int, it is valid to form the type int T::* anyway for any class (you just couldn't make that pointer-to-member refer to any member if the type doesn't have an int member).
The std::is_class type trait is expressed through a compiler intrinsic (called __is_class on most popular compilers), and it cannot be implemented in "normal" C++.
Those manual C++ implementations of std::is_class can be used in educational purposes, but not in a real production code. Otherwise bad things might happen with forward-declared types (for which std::is_class should work correctly as well).
Here's an example that can be reproduced on any msvc x64 compiler.
Suppose I have written my own implementation of is_class:
namespace detail
{
template<typename T>
constexpr char test_my_bad_is_class_call(int T::*) { return {}; }
struct two { char _[2]; };
template<typename T>
constexpr two test_my_bad_is_class_call(...) { return {}; }
}
template<typename T>
struct my_bad_is_class
: std::bool_constant<sizeof(detail::test_my_bad_is_class_call<T>(nullptr)) == 1>
{
};
Let's try it:
class Test
{
};
static_assert(my_bad_is_class<Test>::value == true);
static_assert(my_bad_is_class<const Test>::value == true);
static_assert(my_bad_is_class<Test&>::value == false);
static_assert(my_bad_is_class<Test*>::value == false);
static_assert(my_bad_is_class<int>::value == false);
static_assert(my_bad_is_class<void>::value == false);
As long as the type T is fully defined by the moment my_bad_is_class is applied to it for the first time, everything will be okay. And the size of its member function pointer will remain what it should be:
// 8 is the default for such simple classes on msvc x64
static_assert(sizeof(void(Test::*)()) == 8);
However, things become quite "interesting" if we use our custom type trait with a forward-declared (and not yet defined) type:
class ProblemTest;
The following line implicitly requests the type int ProblemTest::* for a forward-declared class, definition of which cannot be seen by the compiler right now.
static_assert(my_bad_is_class<ProblemTest>::value == true);
This compiles, but, unexpectedly, breaks the size of a member function pointer.
It seems like the compiler attempts to "instantiate" (similarly to how templates are instantiated) the size of a pointer to ProblemTest's member function in the same moment that we request the type int ProblemTest::* within our my_bad_is_class implementation. And, currently, the compiler cannot know what it should be, thus it has no choice but to assume the largest possible size.
class ProblemTest // definition
{
};
// 24 BYTES INSTEAD OF 8, CARL!
static_assert(sizeof(void(ProblemTest::*)()) == 24);
The size of a member function pointer was trippled! And it cannot be shrunk back even after the definition of class ProblemTest has been seen by the compiler.
If you work with some third party libraries that rely on particular sizes of member function pointers on your compiler (e.g., the famous FastDelegate by Don Clugston), such unexpected size changes caused by some call to a type trait might be a real pain. Primarily because type trait invocations are not supposed to modify anything, yet, in this particular case, they do -- and this is extremely unexpected even for an experienced developer.
On the other hand, had we implemented our is_class using the __is_class intrinsic, everything would have been OK:
template<typename T>
struct my_good_is_class
: std::bool_constant<__is_class(T)>
{
};
class ProblemTest;
static_assert(my_good_is_class<ProblemTest>::value == true);
class ProblemTest
{
};
static_assert(sizeof(void(ProblemTest::*)()) == 8);
Invocation of my_good_is_class<ProblemTest> does not break any sizes in this case.
So, my advice is to rely on the compiler intrinsics when implementing your custom type traits like is_class wherever possible. That is, if you have a good reason to implement such type traits manually at all.
What does the T::* mean? Also, is this not a function declaration? It looks like one, yet this compiles without defining a function body.
The int T::* is a pointer to member object. It can be used as follows:
struct T { int x; }
int main() {
int T::* ptr = &T::x;
T a {123};
a.*ptr = 0;
}
Once again, is this not a function declaration with no body ever defined? Also what does the ellipsis mean in this context?
In the other line:
template<class T> two test(...);
the ellipsis is a C construct to define that a function takes any number of arguments.
I would like to understand what this code is doing.
Basically it's checking if a specific type is a struct or a class by checking if 0 can be interpreted as a member pointer (in which case T is a class type).
Specifically, in this code:
namespace detail {
template <class T> char test(int T::*);
struct two{
char c[2];
};
template <class T> two test(...);
}
you have two overloads:
one that is matched only when a T is a class type (in which case this one is the best match and "wins" over the second one)
on that is matched every time
In the first the sizeof the result yields 1 (the return type of the function is char), the other yields 2 (a struct containing 2 chars).
The boolean value checked is then:
sizeof(detail::test<T>(0)) == 1 && !std::is_union<T>::value
which means: return true only if the integral constant 0 can be interpreted as a pointer to member of type T (in which case it's a class type), but it's not a union (which is also a possible class type).
Test is an overloaded function that either takes a pointer to member in T or anything. C++ requires that the best match be used. So if T is a class type it can have a member in it...then that version is selected and the size of its return is 1. If T is not a class type then T::* make zero sense so that version of the function is filtered out by SFINAE and won't be there. The anything version is used and it's return type size is not 1. Thus checking the size of the return of calling that function results in a decision whether the type might have members...only thing left is making sure it's not a union to decide if it's a class or not.
Here is standard wording:
[expr.sizeof]:
The sizeof operator yields the number of bytes occupied by a non-potentially-overlapping object of the type of its operand.
The operand is either an expression, which is an unevaluated operand
([expr.prop])......
2. [expr.prop]:
In some contexts, unevaluated operands appear ([expr.prim.req], [expr.typeid], [expr.sizeof], [expr.unary.noexcept], [dcl.type.simple], [temp]).
An unevaluated operand is not evaluated.
3. [temp.fct.spec]:
[Note: Type deduction may fail for the following reasons:
...
(11.7) Attempting to create “pointer to member of T” when T is not a class type.
[ Example:
template <class T> int f(int T::*);
int i = f<int>(0);
— end example
]
As above shows, it is well-defined in standard :-)
4. [dcl.meaning]:
[Example:
struct X {
void f(int);
int a;
};
struct Y;
int X::* pmi = &X::a;
void (X::* pmf)(int) = &X::f;
double X::* pmd;
char Y::* pmc;
declares pmi, pmf, pmd and pmc to be a pointer to a member of X of type int, a pointer to a member of X of type void(int), a pointer to a member ofX of type double and a pointer to a member of Y of type char respectively.The declaration of pmd is well-formed even though X has no members of type double. Similarly, the declaration of pmc is well-formed even though Y is an incomplete type.

Why does Boost MPL have integral constants?

Since you can take integral values as template parameters and perform arithmetic on them, what's the motivation behind boost::mpl::int_<> and other integral constants? Does this motivation still apply in C++11?
You can take integral values as template parameters, but you cannot take both types and non-type template parameters with a single template. Long story short, treating non-type template parameters as types allows for them to be used with a myriad of things within MPL.
For instance, consider a metafunction find that works with types and looks for an equal type within a sequence. If you wished to use it with non-type template parameters you would need to reimplement new algorithms 'overloads', a find_c for which you have to manually specify the type of the integral value. Now imagine you want it to work with mixed integral types as the rest of the language does, or that you want to mix types and non-types, you get an explosion of 'overloads' that also happen to be harder to use as you have to specify the type of each non-type parameter everywhere.
This motivation does still apply in C++11.
This motivation will still apply to C++y and any other version, unless we have some new rule that allows conversion from non-type template parameters to type template parameters. For instance, whenever you use 5 and the template requests a type instantiate it with std::integral_constant< int, 5 > instead.
tldr; Encoding a value as a type allows it to be used in far more places than a simple value. You can overload on types, you can't overload on values.
K-Ballo's answer is great.
There's something else I think is relevant though. The integral constant types aren't only useful as template parameters, they can be useful as function arguments and function return types (using the C++11 types in my examples, but the same argument applies to the Boost ones that predate them):
template<typename R, typename... Args>
std::integral_constant<std::size_t, sizeof...(Args)>
arity(R (*)(Args...))
{ return {}; }
This function takes a function pointer and returns a type telling you the number of arguments the function takes. Before we had constexpr functions there was no way to call a function in a constant expression, so to ask questions like "how many arguments does this function type take?" you'd need to return a type, and extract the integer value from it.
Even with constexpr in the language (which means the function above could just return sizeof...(Args); and that integer value would be usable at compile time) there are still good uses for integral constant types, e.g. tag dispatching:
template<typename T>
void frobnicate(T&& t)
{
frob_impl(std::forward<T>(t), std::is_copy_constructible<T>{});
}
This frob_impl function can be overloaded based on the integer_constant<bool, b> type passed as its second argument:
template<typename T>
void frob_impl(T&& t, std::true_type)
{
// do something
}
template<typename T>
void frob_impl(T&& t, std::false_type)
{
// do something else
}
You could try doing something similar by making the boolean a template parameter:
frob_impl<std::is_copy_constructible<T>::value>(std::forward<T>(t));
but it's not possible to partially specialize a function template, so you couldn't make frob_impl<true, T> and frob_impl<false, T> do different things. Overloading on the type of the boolean constant allows you to easily do different things based on the value of the "is copy constructible" trait, and that is still very useful in C++11.
Another place where the constants are useful is for implementing traits using SFINAE. In C++03 the conventional approach was to have overloaded functions that return two types with different sizes (e.g an int and a struct containing two ints) and test the "value" with sizeof. In C++11 the functions can return true_type and false_type which is far more expressive, e.g. a trait that tests "does this type have a member called foo?" can make the function indicating a positive result return true_type and make the function indicating a negative result return false_type, what could be more clear than that?
As a standard library implementor I make very frequent use of true_type and false_type, because a lot of compile-time "questions" have true/false answers, but when I want to test something that can have more than two different results I will use other specializations of integral_constant.