如何在编译时连接静态字符串? [英] How to concatenate static strings at compile time?

查看:56
本文介绍了如何在编译时连接静态字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用模板来创建 type_info :: name()函数的类似物,该函数会发出 const 限定的名称.例如. typeid(bool const).name()"bool" ,但我想查看"bool const" .因此,对于通用类型,我定义:

  template< class T>struct type_name {static char const * const _;};模板< T类>char const * const type_name< T> :: _ =未知类型";char const * const type_name< bool> :: _ ="bool";char const * const type_name< int> :: _ ="int";//等等. 

然后 type_name< bool> :: _ "bool" .对于非const类型,显然我可以为每种类型添加一个单独的定义,因此 char const * const type_name< bool const> :: _ ="bool const"; 等.但是我想我会尝试部分专业化和连接宏,可在一行中为任何先前定义了非 const 限定名称的类型在一行中获得const限定名称.所以

  #define CAT(A,B)A B模板< T类>char const * const type_name< T const> :: _= CAT(type_name< T> :: _,"const");//行[1] 

但是然后 type_name< bool const> :: _ 给了我错误C2143:语法错误:缺少';'第[1] 行的"string" 之前.我认为 type_name< bool> :: _ 是在编译时已知的静态字符串,那么如何在编译时将它与"const" 并置?>

我尝试了更简单的示例,但存在相同的问题:

  char str1 [4] ="int";char * str2 = MYCAT(str1,"const"); 

解决方案

我最近重新研究了这个问题,发现我给出的先前答案在连接多个字符串时产生了可笑的长编译时间.

我已经开发出了一种新的解决方案,该方法利用constexpr函数来删除负责较长编译时间的递归模板.

  #include< array>#include< iostream>#include< string_view>模板< std :: string_view const& ... Strs>结构联接{//将所有字符串连接到一个字符的std :: array中静态constexpr auto impl()noexcept{constexpr std :: size_t len =(Strs.size()+ ... + 0);std :: array< char,len + 1>arr {};自动附加= [i = 0,& arr](自动const& s)可变{对于(auto c:s)arr [i ++] = c;};(append(Strs),...);arr [len] = 0;返回arr;}//给连接的字符串静态存储静态constexpr auto arr = impl();//查看为std :: string_view静态constexpr std :: string_view值{arr.data(),arr.size()-1};};//帮助者获得价值模板< std :: string_view const& ... Strs>静态constexpr自动join_v = join< Strs ...> :: value;//Hello world示例静态constexpr std :: string_view hello ="hello";静态constexpr std :: string_view space ="" ;;静态constexpr std :: string_view world ="world";静态constexpr std :: string_view bang =!"//一起加入静态constexpr自动加入= join_v" hello,space,world,bang> ;;int main(){std :: cout<<已加入<<'\ n';} 

即使使用大量要串联的字符串,这也可以缩短编译时间.

我个人认为此解决方案更易于遵循,因为 constexpr impl 函数类似于在运行时如何解决此问题.

编辑,借助@ Jarod42

进行了改进

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");

解决方案

I recently revisited this problem, and found that the previous answer I gave produced ridiculously long compile times when concatenating more than a handful of strings.

I have produced a new solution which leverages constexpr functions to remove the recursive templates responsible for the long compilation time.

#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';
}

This gives much quicker compile times, even with a large quantity of strings to concatenate.

I personally find this solution easier to follow as the constexpr impl function is akin to how this could be solved at runtime.

Edited with improvements thanks to @Jarod42

这篇关于如何在编译时连接静态字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆