Estou tentando fazer o seguinte código funcionar:
#include <string>
#include <tuple>
#include <print>
template<char Specifier>
struct ParseSpecifier;
template<>
struct ParseSpecifier<'s'>
{
static void parse()
{
std::println("string");
}
};
template<>
struct ParseSpecifier<'i'>
{
static void parse()
{
std::println("integer");
}
};
template<std::size_t Index>
void parse_format(const std::string_view format)
{
if (Index == format.size())
return;
ParseSpecifier<format[Index]>::parse();
parse_format<Index + 1>(format);
}
int main()
{
parse_format<0>("iiisss");
}
Eu sei que existem bibliotecas (como fmt) que podem compilar strings de formato de validação de tempo, então isso deve ser possível de alguma forma. Devo observar que o objetivo final não é imprimir "string"
and "integer"
, mas sim criar um std::tuple
baseado em i
e s
s na string fornecida. A string sempre será conhecida em tempo de compilação.
Estou começando aos poucos, pois estou apenas aprendendo metaprogramação de modelos. Como posso fazer um código como esse funcionar? Eu entendo que o formato não é constexpr
como os parâmetros de função não podem ser. Além disso, std::string_view
não pode ser um parâmetro de modelo. Se eu usar template<char... Chars>
então terei que chamar a função like parse_format<0, 'i', 's', 's', 'i', 's'>();
, o que é horrível.
Existe alguma maneira de fazer com que minha tentativa de código funcione? Caso contrário, qual é a melhor estratégia para validação de strings em tempo de compilação?
Observação importante: a função final será chamada com um parâmetro conhecido em tempo de compilação e um parâmetro em tempo real (muito parecido fmt::format
).
Edição fácil: https://godbolt.org/z/s8eoYarja
A maneira como libfmt (e
std::format
) faz isso é passando uma classe personalizada em vez destd::string_view
, com umconsteval
construtor aceitando uma string. O referido construtor é executado em tempo de compilação e pode, por exemplo, lançar (ou fazer outra coisa) para causar um erro em tempo de compilação.Mas essa abordagem não permite que você faça isso:
Isso requer passar a string como parâmetro do modelo:
Ou com uma sintaxe de chamada ligeiramente diferente: