The main motivation behind wanting a string literal with external linkage is to use string literals as non-type template parameters.
I would imagine a string literal with external linkage having a definition similar to
A string-literal that has an e in the prefix is a string-literal with external linkage.
template<auto&> struct S{}; void bar() { S<e"foo"> s; }
will have behaviour equivalent to
template<auto&> struct S{}; constexpr char __foo[] = "foo"; void bar { S<__foo> s; }
Is there a reason not to have external linkage string literals?
Does somehow adding another prefix (like e"Lorem Ipsum"
) to make a string literal have external linkage detrimental?
Note: it is already possible to achieve an external linkage string, but it is a god awful way to do things.
#include<boost/metaparse/v1/string.hpp>
template<typename>
struct hack;
template<char... Cs>
struct hack<boost::metaparse::v1::string<Cs...>>
{
static constexpr char arr[] = {Cs..., '\0'};
};
#define E(str) hack<BOOST_METAPARSE_STRING(str)>::arr
template<auto&> struct S{};
S<E("I'm an external linkage string")> s; // compiles
Boost uses a python script to generate the implementation of BOOST_METAPARSE_STRING
, and that is terrible.
The question is about to become moot in C++20 due to P0732 class types in non-type template parameters.
Non-type template parameters are the last vestiges of an asymmetry between fundamental types and class types. It was there not through choice but by necessity: it wasn't clear how linkers are supposed to deal with them.
Linkers need to be able to differentiate between two template class and in order to do that, it needs to answer whether two objects, a
and b
are equal. It was trivial for fundamental types, but unsolvable for class types with the tools available prior C++20.
P0515 consistent comparison gave the mechanism for determining whether two class type objects are equal, provided they have trivial operator<=>
, which has the semantics of memberwise comparison.
If P0732 goes through, you would be able to write
template<size_t N>
struct fixed_string
{
constexpr fixed_string(const char (&str)[N]) { std::copy(str, str + N, data); }
auto operator<=>(const fixed_string&, const fixed_string&) = default;
char data[N];
};
template<size_t N>
fixed_string(const char(&)[N]) -> fixed_string<N>;
template<fixed_string> struct S {};
S<"foo"> s;
See also thoughts on the text formatting library that is favored to go into C++20 as well.
It's possible to parse strings using constexpr functions only. Here's a very simple example:
constexpr int placeholder_count(const char* s, size_t i = 0, int result = 0)
{
return s[i] == 0
? result
: (s[i] == '%')
? placeholder_count(s, i + 1, result + 1)
: placeholder_count(s, i + 1, result);
}
int main()
{
static_assert(placeholder_count("foo %s bar %d") == 2, "");
return 0;
}
https://wandbox.org/permlink/TwN0UALpp0e6qfqr
You can implement a lot of practical stuff using this, especially if C++14 is allowed, much less recursion is needed then.
For more advanced use-cases, check-out metaparse: http://www.boost.org/doc/libs/1_64_0/doc/html/metaparse.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With