I am trying to use templates to create an analogue of the type_info::name()
function which emits the const
-qualified name. E.g. typeid(bool const).name()
is "bool"
but I want to see "bool const"
. So for generic types I define:
template<class T> struct type_name { static char const *const _; };
template<class T> char const *const type_name<T>::_ = "type unknown";
char const *const type_name<bool>::_ = "bool";
char const *const type_name<int>::_ = "int";
//etc.
Then type_name<bool>::_
is "bool"
. For non-const types obviously I could add a separate definition for each type, so char const *const type_name<bool const>::_ = "bool const";
etc. But I thought I would try a partial specialization and a concatenation macro to derive in one line the const-qualified name for any type which has its non-const
-qualified name previously defined. So
#define CAT(A, B) A B
template<class T> char const *const type_name<T const>::_
= CAT(type_name<T>::_, " const"); // line [1]
But then type_name<bool const>::_
gives me error C2143: syntax error: missing ';' before 'string'
for line [1]
. I think that type_name<bool>::_
is a static string known at compile time, so how do I get it concatenated with " const"
at compile time?
I tried more simple example but same problem:
char str1[4] = "int";
char *str2 = MYCAT(str1, " const");
Yes, in your case*1 string concatenation requires all characters to be copied, this is a O(N+M) operation (where N and M are the sizes of the input strings). M appends of the same word will trend to O(M^2) time therefor.
There are two ways to concatenate strings in Java: By + (String concatenation) operator. By concat() method.
String concatenation It can be a bit surprising, but this code actually runs in O(N2) time. The reason is that in Java strings are immutable, and as a result, each time you append to the string new string object is created. The loop in the code does 1 + 2 + 3 + ...
Building on @Hededes answer, if we allow recursive templates, then concatenation of many strings can be implemented as:
#include <string_view>
#include <utility>
#include <iostream>
namespace impl
{
/// Base declaration of our constexpr string_view concatenation helper
template <std::string_view const&, typename, std::string_view const&, typename>
struct concat;
/// Specialisation to yield indices for each char in both provided string_views,
/// allows us flatten them into a single char array
template <std::string_view const& S1,
std::size_t... I1,
std::string_view const& S2,
std::size_t... I2>
struct concat<S1, std::index_sequence<I1...>, S2, std::index_sequence<I2...>>
{
static constexpr const char value[]{S1[I1]..., S2[I2]..., 0};
};
} // namespace impl
/// Base definition for compile time joining of strings
template <std::string_view const&...> struct join;
/// When no strings are given, provide an empty literal
template <>
struct join<>
{
static constexpr std::string_view value = "";
};
/// Base case for recursion where we reach a pair of strings, we concatenate
/// them to produce a new constexpr string
template <std::string_view const& S1, std::string_view const& S2>
struct join<S1, S2>
{
static constexpr std::string_view value =
impl::concat<S1,
std::make_index_sequence<S1.size()>,
S2,
std::make_index_sequence<S2.size()>>::value;
};
/// Main recursive definition for constexpr joining, pass the tail down to our
/// base case specialisation
template <std::string_view const& S, std::string_view const&... Rest>
struct join<S, Rest...>
{
static constexpr std::string_view value =
join<S, join<Rest...>::value>::value;
};
/// Join constexpr string_views to produce another constexpr string_view
template <std::string_view const&... Strs>
static constexpr auto join_v = join<Strs...>::value;
namespace str
{
static constexpr std::string_view a = "Hello ";
static constexpr std::string_view b = "world";
static constexpr std::string_view c = "!";
}
int main()
{
constexpr auto joined = join_v<str::a, str::b, str::c>;
std::cout << joined << '\n';
return 0;
}
I used c++17 with std::string_view
as the size
method is handy, but this could easily be adapted to use const char[]
literals as @Hedede did.
This answer is intended as a response to the title of the question, rather than the more niche problem described.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With