Obviamente, podemos concatenar dois literais de string em uma constexpr
função, mas e a concatenação de um literal de string com uma string retornada por outra constexpr
função, como no código abaixo?
template <class T>
constexpr const char * get_arithmetic_size()
{
switch (sizeof(T))
{
case 1: return "1";
case 2: return "2";
case 4: return "4";
case 8: return "8";
case 16: return "16";
default: static_assert(dependent_false_v<T>);
}
}
template <class T>
constexpr std::enable_if_t<std::is_arithmetic_v<T>, const char *> make_type_name()
{
const char * prefix = std::is_signed_v<T> ? "int" : "uint";
return prefix; // how to concatenate prefix with get_arithmetic_size<T>() ?
}
static_assert(strings_equal(make_type_name<int>, make_type_name<int32_t>);
O código cria um identificador de seqüência independente do compilador de um tipo aritmético.
EDIT1:
Um exemplo um pouco mais complicado é:
template<typename Test, template<typename...> class Ref>
struct is_specialization : std::false_type {};
template<template<typename...> class Ref, typename... Args>
struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
template <class T>
constexpr std::enable_if_t<is_specialization<T, std::vector>::value || is_specialization<T, std::list>::value, const char *> make_type_name()
{
return "sequence"; // + make_type_name<typename T::value_type>;
}
static_assert(strings_equal(make_type_name<std::vector<int>>(), make_type_name<std::list<int>>()));
std::array
(e provavelmente + modelos variados)typeid
operador. Parte do motivotypeid
é parte do idioma (por exemplo, suportado por uma palavra-chave de idioma dedicado), em vez de uma função de biblioteca, pois sua implementação depende de "magia do compilador" - não é possível implementá-lo no idioma sem o suporte dedicado da implementação. .Respostas:
Aqui está uma classe de sequência de tempo de compilação rápida:
você pode usá-lo assim:
o que leva a declarações como:
passagem.
Exemplo ao vivo .
Agora, uma coisa irritante é que o comprimento do buffer está no sistema de tipos. Você pode adicionar um
length
campo, tornarN
"tamanho do buffer" e modificarct_str
para copiar somente atélength
e deixar os bytes finais como0
. Em seguida, substituacommon_type
para retornar o máximoN
de ambos os lados.Isso permitiria que você passar
ct_str{"uint"}
ect_str{"int"}
no mesmo tipo de valor e tornar o código de implementação um pouco menos irritante.As implementações de funções agora se tornam:
o que é muito mais natural de se escrever.
Exemplo ao vivo .
fonte
else
emget_arithmetic_size
comif constexpr
mesmo se vocêreturn
, porque semelse
a afirmaçãodependent_false_v<T>
irá falhar.Não, é impossível. Você pode implementar algo como abaixo (é C ++ 14).
https://ideone.com/BaADaM
Se você não gosta de usar
<cmath>
, pode substituirstd::log
:fonte
std::log
é muito complicado para mim, preciso de alguma técnica genérica para concatenar stringsconstexpr
, não se preocupestd::log()
. Você pode substituí-lo, mas o código será ampliado.std::log
nemstd::strcmp
é garantido que não sejaconstexpr
. De fato, o padrão proíbe-os especificamenteconstexpr
desde o C ++ 14. Portanto, seu código realmente usa extensões não padrão.