5

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.

Passer By
  • 19,325
  • 6
  • 49
  • 96
  • You don't need strings as non-type template arguments to make this work. (I've done it) You can iterate your string literal using a recursive constexpr function. – erenon Jun 21 '17 at 18:57
  • @erenon That forgoes the compile erorr part doesn't it? And also, that is just an example, my main issue is stated as in the title. I've ran into this more than once by now. – Passer By Jun 21 '17 at 19:02
  • 6
    String literals don't have linkage since only names have linkage and string literals don't have names. In your example `__foo` is not a string literal. `"foo"` is. – user7860670 Jun 21 '17 at 19:15
  • @VTT I'm not suggesting `__foo` is a string literal, I'm saying the behaviour be *as if* the bottom code is generated. And also, the double underscore is there to imply that that is not actually a real variable – Passer By Jun 23 '17 at 08:21

3 Answers3

5

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.

Passer By
  • 19,325
  • 6
  • 49
  • 96
2

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

erenon
  • 18,838
  • 2
  • 61
  • 93
  • I appreciate this, but seriously, the question isn't stated as *how do I parse things at compile time*. I do want to know if having external linkage string literals is a Bad Idea – Passer By Jun 21 '17 at 19:08
  • 1
    @PasserBy: please elaborate your use-case. This technique is suitable to do the printf check you mention in the question, including the compile errors. – erenon Jun 21 '17 at 19:09
2

§ 3.5 Program and linkage [basic.link]

  1. A name is said to have linkage when it might denote the same object, reference, function, type, template, namespace or value as a name introduced by a declaration in another scope

As mentioned in the comments, only names have linkage. String literals aren't names.

§ 2.13.5 String literals [lex.string]

  1. Evaluating a string-literal results in a string literal object with static storage duration, initialized from the given characters as specified above. Whether all string literals are distinct (that is, are stored in nonoverlapping objects) and whether successive evaluations of a string-literal yield the same or a different object is unspecified.

So the actual issue is that different string literals with equal value can be stored in different objects. Even more, successive evaluations of the same literal can yield different objects.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • I'll clarify a bit more, but I'm not asking what the standard says *now*, I'm asking whether changing it will be bad – Passer By Jun 23 '17 at 08:50
  • In response to your statement of the actual issue, I argue that if there were strings with external linkage, they would have different semantics, most likely including it must yield the same object when evaluated – Passer By Jun 23 '17 at 09:00