如何在编译时连接静态字符串
How to concatenate static strings at compile time?
我试图使用模板创建type_info::name()
函数的模拟,该函数发出const
限定名称。例:typeid(bool const).name()
是"bool"
,但我想看到"bool const"
。所以对于泛型类型,我定义:
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.
则type_name<bool>::_
为"bool"
。对于非const类型,显然我可以为每种类型添加单独的定义,例如char const *const type_name<bool const>::_ = "bool const";
等。但我想我会尝试部分专门化和串联宏,在一行中派生出任何类型的const限定名称,该类型具有先前定义的非const
限定名称。所以
#define CAT(A, B) A B
template<class T> char const *const type_name<T const>::_
= CAT(type_name<T>::_, " const"); // line [1]
但是type_name<bool const>::_
给我error C2143: syntax error: missing ';' before 'string'
代替line [1]
。我认为type_name<bool>::_
是在编译时已知的静态字符串,那么我如何在编译时将其与" const"
连接起来?
我尝试了更简单的例子,但同样的问题:
char str1[4] = "int";
char *str2 = MYCAT(str1, " const");
我最近重新研究了这个问题,发现我之前给出的答案在连接多个字符串时产生了可笑的长编译时间。
我已经产生了一个新的解决方案,它利用constexpr函数来删除导致长编译时间的递归模板。
#include <array>
#include <iostream>
#include <string_view>
template <std::string_view const&... Strs>
struct join
{
// Join all strings into a single std::array of chars
static constexpr auto impl() noexcept
{
constexpr std::size_t len = (Strs.size() + ... + 0);
std::array<char, len + 1> arr{};
auto append = [i = 0, &arr](auto const& s) mutable {
for (auto c : s) arr[i++] = c;
};
(append(Strs), ...);
arr[len] = 0;
return arr;
}
// Give the joined string static storage
static constexpr auto arr = impl();
// View as a std::string_view
static constexpr std::string_view value {arr.data(), arr.size() - 1};
};
// Helper to get the value out
template <std::string_view const&... Strs>
static constexpr auto join_v = join<Strs...>::value;
// Hello world example
static constexpr std::string_view hello = "hello";
static constexpr std::string_view space = " ";
static constexpr std::string_view world = "world";
static constexpr std::string_view bang = "!";
// Join them all together
static constexpr auto joined = join_v<hello, space, world, bang>;
int main()
{
std::cout << joined << 'n';
}
这大大缩短了编译时间,即使有大量的字符串要连接。
我个人觉得这个解决方案更容易遵循,因为constexpr impl
函数类似于如何在运行时解决这个问题。
编辑与改进感谢@Jarod42
EDIT -查看我的新改进的答案。
基于@Hededes的答案,如果我们允许递归模板,那么许多字符串的连接可以实现为:
#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;
}
我使用带有std::string_view
的c++17,因为size
方法很方便,但这可以很容易地适应使用const char[]
字面量,如@Hedede所做的。
这个答案是为了回答问题的标题,而不是更利基的问题。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- #为""定义宏;静态";针对不同的上下文
- cmake如何在fedora工作站中找到boost静态库包
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- cmake在我的项目中所需的所有静态库都不成功
- C++从另一个类访问公共静态向量的正确方法是什么
- 当套接字连接断开时检测C/C++Unix
- 基于boost的程序的静态链接——zlib问题
- 在静态库中嵌入类方法
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 如何在C++中获得"静态纯虚拟"功能?
- 我如何将静态网格连接到演员
- 使用静态IP地址时,ESP32 httpclient连接拒绝了
- Qt:如何将不同类别的静态信号连接到插槽
- C++ OpenMP:将 for 循环拆分为静态偶数块,并在最后连接数据
- 是否可以在没有接收器实例的情况下将信号连接到静态插槽
- 安装可可荚后,现有的静态库不使用libssl.A表示TLS连接和访问不良
- 如何在编译时连接静态字符串
- 如何在静态方法中将信号连接到插槽