constexpr来连接两个或多个char字符串 [英] constexpr to concatenate two or more char strings

查看:124
本文介绍了constexpr来连接两个或多个char字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我试图创建一个constexpr函数,它将连接任意数量的字符数组,通过Xeo的下面的回答,连接两个字符数组。 > http://stackoverflow.com/a/13294458/1128289

  #include< array> 

模板< unsigned ... Is> struct seq {};
template< unsigned N,unsigned ... Is>
struct gen_seq:gen_seq< N-1,N-1,Is ...> {};
template< unsigned ... Is>
struct gen_seq< 0,Is ...> :seq< Is ...> {};

模板<无符号N1,无符号... I1,无符号N2,无符号... I2>
constexpr std :: array< char const,N1 + N2-1> const char(const const& a1)[N1],char const(& a2)[N2],seq ,seq a1 [I1] ...,a2 [I2] ...}};
}

模板<无符号N1,无符号N2>
constexpr std :: array< char const,N1 + N2-1> concat(char const(& a1)[N1],char const(& a2)[N2]){
return concat(a1,a2,gen_seq< N1-1> {},gen_seq< N2& });
}

我的尝试到目前为止:

  #include< iostream> 
#include< array>

模板< unsigned ... Is> struct seq {};
template< unsigned N,unsigned ... Is>
struct gen_seq:gen_seq< N-1,N-1,Is ...> {};
template< unsigned ... Is>
struct gen_seq< 0,Is ...> :seq< Is ...> {};

模板<无符号N1,无符号... I1,无符号N2,无符号... I2>
constexpr const std :: array< char,N1 + N2-1>
concat_impl(
const char(& a1)[N1],const char(& a2)[N2],seq ,seq
{
return {{a1 [I1] ...,a2 [I2] ...}};
}

模板<无符号N1,无符号N2>
constexpr const std :: array< char,N1 + N2-1>
concat(const char(& a1)[N1],const char(& a2)[N2])
{
return concat_impl(a1,a2,gen_seq< N1-1& {},gen_seq< N2> {});
}

模板<无符号N1,无符号N2,类... US>
constexpr auto
concat(const char(& a1)[N1],const char(& a2)[N2],const Us& ... xs)
- std :: array< char,N1 + decltype(concat(a2,xs ...)):: size()
{
return concat(a1,concat(a2,xs ...));
}

int main()
{
auto const s = concat(hi,there!
std :: cout<< s.data()<< std :: endl;
//编译错误:
auto const t = concat(hi,there,how,are,you?
std :: cout<< t.data()<< std :: endl;
}

gcc 4.9和clang 3.5都会提供错误,可以找到 decltype 表达式中的 concat 。



clang:

 错误:没有匹配的函数调用'concat'
auto const t = concat(hi有,如何,是,你?
^ ~~~~~
ctconcat.cpp:105:16:注意:候选模板忽略:替换失败[使用N1 = 4,N2 = 7,Us =< char [5] (const char(& a1)[N1],const char(& a2)[N2]),没有匹配的函数用于调用'concat'
constexpr auto concat ,const Us& ... xs) - > std :: array< char,N1 + decltype(concat(a2,xs ...)):: size()
^ ~~~~~~
ctconcat.cpp:62:43:注意:候选函数模板不可行:需要2个参数,但提供了5个
constexpr const std :: array< char,N1 + N2-1> concat(const char(& a1)[N1],const char(& a2)[N2])
^
1产生错误。

来自gcc和clang的错误都表明第二个 concat 函数模板不是 decltype 表达式中 concat 的候选。只考虑第一个模板。

编辑:相关问题为什么 decltype 不能递归使用。



使用带有可变模板函数的decltype的尾随返回类型

解决方案

  template< size_t S> 
using size = std :: integral_constant< size_t,S> ;;

template< class T,size_t N>
constexpr size< N> length(T const(&)[N]){return {}; }
template< class T,size_t N>
constexpr size< N> length(std :: array< T,N> const&){return {}; }

template< class T>
using length_t = decltype(length(std :: declval< T>()));
constexpr size_t sum_string_sizes(){return 0; }
template< class ... Ts>
constexpr size_t sum_string_sizes(size_t i,Ts ... ts){
return(i?i-1:0)+ sum_sizes(ts ...)
}

然后

 模板
模板<无符号N1,无符号N2,类... US>
constexpr auto
concat(const char(& a1)[N1],const char(& a2)[N2],const Us& ... xs)
- std :: array< char,sum_string_sizes(N1,N2,length_t< Us> :: value ...)+1&
{
return concat(a1,concat(a2,xs ...));
}

除去递归 - decltype



$ b


$ b

 模板< size_t S> 
using size = std :: integral_constant< size_t,S> ;;

template< class T,size_t N>
constexpr size< N> length(T const(&)[N]){return {}; }
template< class T,size_t N>
constexpr size< N> length(std :: array< T,N> const&){return {}; }

template< class T>
using length_t = decltype(length(std :: declval< T>()));

constexpr size_t string_size(){return 0; }
template< class ... Ts>
constexpr size_t string_size(size_t i,Ts ... ts){
return(i?i-1:0)+ string_size(ts ...)
}
template< class ... Ts>
using string_length = size< string_size(length_t< Ts> {} ...)> ;;

template< class ... Ts>
using combined_string = std :: array< char,string_length< Ts ...> {} + 1> ;;

template< class Lhs,Rhs,unsigned ... I1,unsigned ... I2>
constexpr const combined_string< Lhs,Rhs>
concat_impl(Lhs const& lhs,Rhs const& rhs,seq< I1 ...>,seq< I2 ...>)
{
//'\0 '添加对称性:
return {{lhs [I1] ...,rhs [I2] ...,'\0'}};
}

template< class Lhs,Rhs>
constexpr const combined_string< Lhs,Rhs>
concat(Lhs const& lhs,Rhs const& rhs)
{
return concat_impl(
lhs,rhs,
gen_seq< string_length< Lhs> {} {},
gen_seq< string_length< Rhs> {}> {}
);
}

template< class T0,class T1,class ... Ts>
constexpr const combined_string< T0,T1,Ts ...>
concat(T0 const& t0,T1 const& t1,Ts const& ... ts)
{
return concat(t0,concat(t1,ts ...));
}

template< class T>
constexpr const combined_string< T>
concat(T const& t){
return concat(t,);
}
constexpr const combined_string<>
concat(){
return concat();
}

live example


I'm trying to make a constexpr function that will concatenate an arbitrary number of char arrays by working from the following answer by Xeo, which concatenates two char arrays.

http://stackoverflow.com/a/13294458/1128289

#include <array>

template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
  return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

My attempt thus far:

#include <iostream>
#include <array>

template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr const std::array<char, N1+N2-1>
concat_impl(
    const char (&a1)[N1], const char (&a2)[N2], seq<I1...>, seq<I2...>)
{
    return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr const std::array<char, N1+N2-1>
concat(const char (&a1)[N1], const char (&a2)[N2])
{
    return concat_impl(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

template<unsigned N1, unsigned N2, class... Us>
constexpr auto
concat(const char(&a1)[N1], const char(&a2)[N2], const Us&... xs)
-> std::array<char, N1 + decltype(concat(a2, xs...))::size() - 1>
{
    return concat(a1, concat(a2, xs...));
}

int main()
{
    auto const s = concat("hi ", "there!");
    std::cout << s.data() << std::endl;
    // compile error:
    auto const t = concat("hi ", "there ", "how ", "are ", "you?");
    std::cout << t.data() << std::endl;
}

Both gcc 4.9 and clang 3.5 give errors indicating that no function matching the concat inside the decltype expression can be found.

clang:

error: no matching function for call to 'concat'
    auto const t = concat("hi ", "there ", "how ", "are ", "you?");
                   ^~~~~~
ctconcat.cpp:105:16: note: candidate template ignored: substitution failure [with N1 = 4, N2 = 7, Us = <char [5], char [5], char [5]>]: no matching function for call to 'concat'
constexpr auto concat(const char(&a1)[N1], const char(&a2)[N2], const Us&... xs) -> std::array<char, N1 + decltype(concat(a2, xs...))::size() - 1>
               ^                                                                                                   ~~~~~~
ctconcat.cpp:62:43: note: candidate function template not viable: requires 2 arguments, but 5 were provided
constexpr const std::array<char, N1+N2-1> concat(const char (&a1)[N1], const char (&a2)[N2])
                                          ^
1 error generated.

The errors from gcc and clang both indicate that the second concat function template is not a candidate for the concat in the decltype expression. Only the first template is considered. Why is that and how do I fix this?

Edit: Relevant question on why decltype can't be used recursively

trailing return type using decltype with a variadic template function

解决方案

template<size_t S>
using size=std::integral_constant<size_t, S>;

template<class T, size_t N>
constexpr size<N> length( T const(&)[N] ) { return {}; }
template<class T, size_t N>
constexpr size<N> length( std::array<T, N> const& ) { return {}; }

template<class T>
using length_t = decltype(length(std::declval<T>()));
constexpr size_t sum_string_sizes() { return 0; }
template<class...Ts>
constexpr size_t sum_string_sizes( size_t i, Ts... ts ) {
  return (i?i-1:0) + sum_sizes(ts...);
}

then

template
template<unsigned N1, unsigned N2, class... Us>
constexpr auto
concat(const char(&a1)[N1], const char(&a2)[N2], const Us&... xs)
-> std::array<char, sum_string_sizes( N1, N2, length_t<Us>::value... )+1 >
{
  return concat(a1, concat(a2, xs...));
}

which gets rid of the recursion-in-decltype.


Here is a full example using the above approach:

template<size_t S>
using size=std::integral_constant<size_t, S>;

template<class T, size_t N>
constexpr size<N> length( T const(&)[N] ) { return {}; }
template<class T, size_t N>
constexpr size<N> length( std::array<T, N> const& ) { return {}; }

template<class T>
using length_t = decltype(length(std::declval<T>()));

constexpr size_t string_size() { return 0; }
template<class...Ts>
constexpr size_t string_size( size_t i, Ts... ts ) {
  return (i?i-1:0) + string_size(ts...);
}
template<class...Ts>
using string_length=size< string_size( length_t<Ts>{}... )>;

template<class...Ts>
using combined_string = std::array<char, string_length<Ts...>{}+1>;

template<class Lhs, class Rhs, unsigned...I1, unsigned...I2>
constexpr const combined_string<Lhs,Rhs>
concat_impl( Lhs const& lhs, Rhs const& rhs, seq<I1...>, seq<I2...>)
{
  // the '\0' adds to symmetry:
  return {{ lhs[I1]..., rhs[I2]..., '\0' }};
}

template<class Lhs, class Rhs>
constexpr const combined_string<Lhs,Rhs>
concat(Lhs const& lhs, Rhs const& rhs)
{
  return concat_impl(
    lhs, rhs,
    gen_seq<string_length<Lhs>{}>{},
    gen_seq<string_length<Rhs>{}>{}
 );
}

template<class T0, class T1, class... Ts>
constexpr const combined_string<T0, T1, Ts...>
concat(T0 const&t0, T1 const&t1, Ts const&...ts)
{
  return concat(t0, concat(t1, ts...));
}

template<class T>
constexpr const combined_string<T>
concat(T const&t) {
  return concat(t, "");
}
constexpr const combined_string<>
concat() {
  return concat("");
}

live example

这篇关于constexpr来连接两个或多个char字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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