Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a reason string literals can't have external linkage?

Tags:

c++

string

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.

like image 937
Passer By Avatar asked Jun 21 '17 18:06

Passer By


2 Answers

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.

like image 127
Passer By Avatar answered Sep 24 '22 03:09

Passer By


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

like image 40
erenon Avatar answered Sep 23 '22 03:09

erenon