Oczywiście możemy połączyć dwie literały łańcuchowe w constexpr
funkcji, ale co z konkatenacją literału łańcuchowego z łańcuchem zwróconym przez inną constexpr
funkcję, jak w kodzie poniżej?
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>);
Kod czyni identyfikator łańcucha niezależnym od kompilatora typu arytmetycznego.
EDYCJA 1:
Nieco bardziej skomplikowanym przykładem jest:
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
(i prawdopodobnie + szablony variadic)typeid
operator. Częścią tego powodutypeid
jest część języka (np. Obsługiwana przez dedykowane słowo kluczowe w języku), a nie funkcja biblioteczna, ponieważ jego implementacja opiera się na „magii kompilatora” - nie jest możliwe wdrożenie w języku bez specjalnego wsparcia z implementacji .Odpowiedzi:
Oto krótka klasa czasu kompilacji:
możesz użyć tego w następujący sposób:
co prowadzi do stwierdzeń takich jak:
przechodzący.
Przykład na żywo .
Teraz jedną irytującą rzeczą jest to, że długość bufora jest w systemie typów. Możesz dodać
length
pole,N
ustawić „rozmiar bufora” i zmodyfikować,ct_str
aby kopiować tylkolength
i pozostawić końcowe bajty jako0
. Następnie zastąp,common_type
aby zwrócić maksN
z obu stron.Który pozwoli Ci zdać
ct_str{"uint"}
ict_str{"int"}
w tym samym rodzaju wartości i uczynić kod implementacji nieco mniej irytujące.Implementacje funkcji stają się teraz:
co jest dużo bardziej naturalne do napisania.
Przykład na żywo .
źródło
else
wget_arithmetic_size
zeif constexpr
nawet jeśli niereturn
, ponieważ bezelse
twierdzeniedependent_false_v<T>
zawiedzie.Nie, to niemożliwe. Możesz zaimplementować coś takiego jak poniżej (jest to C ++ 14).
https://ideone.com/BaADaM
Jeśli nie lubisz używać
<cmath>
, możesz wymienićstd::log
:źródło
std::log
jest dla mnie zbyt skomplikowane, potrzebuję jakiejś ogólnej techniki łączenia ciągówconstexpr
nie martw sięstd::log()
. Możesz go wymienić, ale kod zostanie powiększony,std::log
niestd::strcmp
ma gwarancji, że tak będzieconstexpr
. W rzeczywistości standard wyraźnie zabrania ich istnieniaconstexpr
od wersji C ++ 14. Dlatego twój kod korzysta z niestandardowych rozszerzeń.