La principal motivación para querer un literal de cadena con enlace externo es usar literales de cadena como parámetros de plantilla que no son de tipo.

Me imagino una cadena literal con enlace externo que tiene una definición similar a

Un string-literal que tiene una e en el prefijo es un string-literal con enlace externo.

template<auto&> struct S{};
void bar()
{
    S<e"foo"> s;
}

tendrá un comportamiento equivalente a

template<auto&> struct S{};
constexpr char __foo[] = "foo";
void bar
{
    S<__foo> s;
}

¿Hay alguna razón para no tener literales de cadena de enlace externo? ¿Agregar de alguna manera otro prefijo (como e"Lorem Ipsum") para hacer que una cadena literal tenga un enlace externo perjudicial?

Nota: ya es posible lograr una cadena de enlace externa, pero es una forma horrible de hacer las cosas.

#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 usa un script de Python para generar la implementación de BOOST_METAPARSE_STRING, y eso es terrible.

4
Passer By 21 jun. 2017 a las 21:54

3 respuestas

La mejor respuesta

La pregunta está a punto de convertirse en discutible en C ++ 20 debido a Tipos de clase P0732 en parámetros de plantilla sin tipo.

Los parámetros de plantilla sin tipo son los últimos vestigios de una asimetría entre tipos fundamentales y tipos de clase. No estaba allí por elección sino por necesidad: no estaba claro cómo se supone que los vinculadores deben tratar con ellos.

Los enlazadores deben ser capaces de diferenciar entre dos clases de plantillas y, para hacerlo, deben responder si dos objetos, a y b son iguales. Era trivial para los tipos fundamentales, pero no se podía resolver para los tipos de clase con las herramientas disponibles antes de C ++ 20.

P0515 comparación consistente proporcionó el mecanismo para determinar si dos objetos de tipo de clase son iguales, siempre que tengan operator<=> trivial, que tiene la semántica de la comparación entre miembros.

Si P0732 pasa, usted sería capaz de escribir

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;

Consulte también pensamientos sobre la biblioteca de formato de texto que se prefiere ir a C ++ 20 también.

5
Passer By 19 mar. 2018 a las 10:12

Es posible analizar cadenas usando solo las funciones constexpr. Aquí hay un ejemplo muy simple:

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

Puede implementar muchas cosas prácticas con esto, especialmente si se permite C ++ 14, entonces se necesita mucha menos recursividad.

Para casos de uso más avanzados, desproteja metaparse: http://www.boost.org/doc/libs/ 1_64_0 / doc / html / metaparse.html

2
erenon 21 jun. 2017 a las 19:05

§ 3.5 Programa y vinculación [basic.link]

  1. Se dice que un nombre tiene enlace cuando puede denotar el mismo objeto, referencia, función, tipo, plantilla, espacio de nombres o valor que un nombre introducido por una declaración en otro ámbito

Como se menciona en los comentarios, solo los nombres tienen vínculos. Los literales de cadena no son nombres.

§ 2.13.5 Literales de cadena [lex.string]

  1. La evaluación de un literal de cadena da como resultado un objeto de literal de cadena con una duración de almacenamiento estático, inicializado a partir de los caracteres dados como especificado arriba. Si todos los literales de cadena son distintos (es decir, se almacenan en objetos no superpuestos) y si son sucesivos las evaluaciones de un literal de cadena producen el mismo objeto o un objeto diferente no está especificado .

Entonces, el problema real es que diferentes literales de cadena con igual valor se pueden almacenar en diferentes objetos. Aún más, las evaluaciones sucesivas del mismo literal pueden producir diferentes objetos.

1
bolov 23 jun. 2017 a las 08:51