如何在编译时重复连接字符串?

How do I concatenate strings repeatedly at compile time?

提问人:Konvt 提问时间:10/19/2023 最后编辑:Konvt 更新时间:10/20/2023 访问量:132

问:

我编写了以下代码用于在编译时使用字符串:

template<char... Chars>
struct CnstString {
    template<char... Aped>
    using push_back = CnstString<Chars..., Aped...>;
    constexpr static char value[] = {Chars...};
};

当我这样使用它时很好:

#include <iostream>
using str = CnstString<'H', 'e', 'l', 'l', 'o', '\0'>;
int main()
{
    std::cout << str << std::endl;
    return 0; // it will output "Hello"
}

我想做的是使用递归模板结构,在编译时拼接上述代码给出的字符串,并在递归端点将 a 附加到数组中。'\0'

我写这段代码的原因是我想多次连接同一个字符串。显然,我不能像 ."Hello""Hello"

递归模板结构如下所示:

template<int N, typename Str>
struct RepeatStr {
    using ret = RepeatStr<N-1, Str>; // this is an error, I don't know how to pass parameters
};
template<typename Str>
struct RepeatStr<-1, Str> {
    using ret = Str:: template push_back<'\0'>;
};

但是,我发现我不知道如何使用 Str 中的字符将字符附加到自身。

有什么问题吗?或者只是在编译时无法做到?

C++ 字符串 C++14 模板元编程

评论

0赞 user12002570 10/19/2023
始终在您的问题中包含错误。
2赞 AndyG 10/19/2023
>显然,我不能像“Hello”“Hello” =>一样将同一个字符串连接在一起;预处理器将连接相邻的字符串文本。演示
0赞 Konvt 10/19/2023
我的意思是,我需要使用一个变量来指定字符串重复的次数,所以我不能使用文字连接directly.@AndyG
0赞 user12002570 10/19/2023
@Konvt 在我之前添加关键字后,请参阅工作演示templatepush_back

答:

1赞 user12002570 10/19/2023 #1

有什么问题吗?

您需要在 using 声明中添加关键字,以告知使用的编译器是模板。templatepush_back

template<int N, typename Str>
struct RepeatStr {
    using ret = RepeatStr<N-1, Str>; 
};
template<typename Str>
struct RepeatStr<-1, Str> {
//--------------------vvvvvvvv------------------->works now
    using ret = Str:: template push_back<'\0'>;    
};

工作演示

3赞 Jarod42 10/20/2023 #2

如果可能的话,我会更改定义,仅将“\0”放在CnstStringvalue

template<char... Chars>
struct CnstString {
    constexpr static char value[] = {Chars..., '\0'};
};

然后提供(稍后将允许折叠表达式 (C++17))operator +

template <char... Cs1, char...Cs2>
CnstString<Cs1..., Cs2...> operator +(CnstString<Cs1...>, CnstString<Cs2...>) { return {}; }

最后,您将具有以下类型的类型:RepeatStr<N, Str>Str{} + .. + Str{}

template<int N, typename Str>
struct RepeatStr {
    // C++20
    using ret = decltype([]<std::size_t... Is>(std::index_sequence<Is...>){
        return ((static_cast<void>(Is), Str{}) + ...);
    }(std::make_index_sequence<N>()));
};

演示

由于您仅限于 C++14,因此将 C++17 的折叠表达式替换为“递归”函数调用:

template <typename T>
auto sum_impl(T t)
{
    return t;
}

template <typename T, typename... Ts>
auto sum_impl(T t, Ts... ts)
{
    return t + sum_impl(ts...);
}

并将模板 lambda(C++20) 替换为常规模板函数:

template <typename Str, std::size_t... Is>
auto repeat_impl(std::index_sequence<Is...>)
{
    return sum_impl((static_cast<void>(Is), Str{})...);
}

template<int N, typename Str>
struct RepeatStr {
    using ret = decltype(repeat_impl<Str>(std::make_index_sequence<N>()));
};

演示

评论

0赞 Konvt 10/20/2023
谢谢。顺便问一下,请问修改后是否可以在 C++11 中使用这段代码?
1赞 Jarod42 10/20/2023
对于 C++11,您必须自己实现 std::index_sequence。SO 上有几篇帖子。