在编译时将两个常量字符串(或数组)组合成一个常量字符串(或数组)

non*_*all 6 c++ arrays const concatenation c++11

在C#和Java中,可以使用一个或多个其他常量字符串创建常量字符串.我试图在C++中实现相同的结果(实际上,在C++ 0x中,具体而言),但是不知道我将使用什么语法来实现它,如果在C++中可以实现这样的话.这是一个说明我想要做的事情的例子:

#include <stdio.h>

const char array1[] = "Hello ";
const char array2[] = "world!\n";
const char array3[] = array1 + array2; // C++ doesn't like it when I try this

int main() {

    printf(array3);

    return 0;

}
Run Code Online (Sandbox Code Playgroud)

有什么指针吗?(没有双关语.)

编辑:我需要能够将它应用于整数数组 - 而不仅仅是char数组.但是,在这两种情况下,待组合数组都是固定大小的并且是编译时常量.

Edw*_*nge 7

所以...

您不希望进行运行时连接.

您不想使用预处理器.

您希望使用常量和输出常量.

好.但你不会喜欢它:

#include <boost/mpl/string.hpp>

#include <iostream>

int main()
{
  using namespace boost::mpl;

  typedef string<'Hell', 'o '> hello;
  typedef string<'Worl', 'd!'> world;
  typedef insert_range<hello, end<hello>::type, world>::type hello_world;

  std::cout << c_str<hello_world>::value << std::endl;

  std::cin.get();
}
Run Code Online (Sandbox Code Playgroud)


SCF*_*nch 5

使用字符串对象:

#include <iostream>
#include <string>

const std::string s1 = "Hello ";
const std::string s2 = "world!\n";
const std::string s3 = s1 + s2;

int main()
{
  std::cout << s3 << std::endl;
}
Run Code Online (Sandbox Code Playgroud)


CTM*_*ser 5

我看了你的问题,发现没有人真的回答过.我回答它的过程需要一整天才能完美,但无论如何我还需要它来完成我的工作.

我的工作需要constexpr,我记住了答案.你的工作没有指明,但它不会伤害.

什么都行不通; 即我的第一次尝试

(我在MacPorts上使用GCC-4.7,使用的是10年前的PowerPC Mac.)

您可以轻松地将(C++ 11)可变参数函数参数列表转换为任何类型的元组:

template < typename Destination, typename ...Source >
constexpr
auto  initialize( Source&& ...args ) -> Destination
{ return Destination{ce_forward<Source>(args)...}; }
Run Code Online (Sandbox Code Playgroud)

(ce_forward函数模板就像std::forward,除了我明确地做了constexpr.)

(当我没有放入Destination正文时,我的编译器给了我与目标无法用a初始化相关的错误std::initialization_list;因此我现在的表单应该使用目标类型支持的任何聚合或构造函数形式.)

但我们最初需要采用其他方式,然后使用上面的代码进行翻译.我试过这样的代码:

template < typename Destination, typename Source, typename Size1, typename Size2, typename ...Args >
constexpr
auto  fill_from_array( Source&& source, Size1 index_begin, Size2 index_end, Args&& ...args )
 -> Destination
{
    return ( index_begin < index_end )
      ? fill_from_array<Destination>( ce_forward<Source>(source), index_begin + 1, index_end, ce_forward<Args>(args)..., ce_forward<Source>(source)[index_begin] )
      : initialize<Destination>( ce_forward<Args>(args)... );
}
Run Code Online (Sandbox Code Playgroud)

(因为我也需要两个来源,所以我做了这个函数的更大版本.)

当我实际运行此代码时,我的计算机在超过虚拟内存一小时后就被淘汰了.我想这会导致无限循环或其他什么.(或者它可能是有限的,但对我的古代系统来说太多了.)

我的第二次尝试

我搜索了SO,直到找到可能有用的东西:

并从那些和我读到的其他东西拼凑出一个解决方案:在编译时解析字符串 - 第一部分.基本上,我们使用initialize上面的函数模板的变体; 我们使用模板可变参数的映射,而不是将初始化器完全基于函数可变参数.

最简单的映射源是非负整数:

#include <cstddef>

template < std::size_t ...Indices >
struct index_tuple
{ using next = index_tuple<Indices..., sizeof...(Indices)>; };

template < std::size_t Size >
struct build_indices
{ using type = typename build_indices<Size - 1>::type::next; };

template < >
struct build_indices< 0 >
{ using type = index_tuple<>; };
Run Code Online (Sandbox Code Playgroud)

index_tuple类模板是什么,我们将通过周围的映射,而build_indices类模板会将index_tuple实例以正确的格式:

index_tuple<>
index_tuple<0>
index_tuple<0, 1>
index_tuple<0, 1, 2>
...
Run Code Online (Sandbox Code Playgroud)

我们index_tuple使用函数模板创建对象:

template < std::size_t Size >
constexpr
auto  make_indices() noexcept -> typename build_indices<Size>::type
{ return {}; }
Run Code Online (Sandbox Code Playgroud)

我们使用所述index_tuple对象来贡献函数模板的模板头:

#include <array>

template < std::size_t N, std::size_t M, std::size_t ...Indices >
constexpr
std::array<char, N + M - 1u>
fuse_strings_impl( const char (&f)[N], const char (&s)[M], index_tuple<Indices...> );
Run Code Online (Sandbox Code Playgroud)

第三个参数没有得到名称,因为我们不需要对象本身.我们只需要标题中的"std :: size_t ... Indices".我们知道在扩展时会变成"0,1,......,X".我们将有序扩展提供给函数调用,该函数调用将扩展为所需的初始值设定项.作为一个例子,让我们看一下上面函数的定义:

template < std::size_t N, std::size_t M, std::size_t ...Indices >
constexpr
std::array<char, N + M - 1u>
fuse_strings_impl( const char (&f)[N], const char (&s)[M], index_tuple<Indices...> )
{ return {{ get_strchr<Indices>(f, s)... }}; }
Run Code Online (Sandbox Code Playgroud)

我们将返回array第一个元素get_strchr<0>(f,s),第二个元素get_strchr<1>(f,s),依此类推.请注意,此函数名称以"_impl"结尾,因为我index_tuple通过调用公共版本来隐藏使用并确保正确的基本情况:

template < std::size_t N, std::size_t M >
constexpr
std::array<char, N + M - 1u>
fuse_strings( const char (&f)[N], const char (&s)[M] )
{ return fuse_strings_impl(f, s, make_indices<N + M - 2>()); }
Run Code Online (Sandbox Code Playgroud)

你可以尝试编码:

#include <iostream>
#include <ostream>

int  main()
{
    using std::cout;
    using std::endl;

    constexpr auto  initialize_test = initialize<std::array<char, 15>>( 'G',
     'o', 'o', 'd', 'b', 'y', 'e', ',', ' ', 'm', 'o', 'o', 'n', '!', '\0' );
    constexpr char  hello_str[] = "Hello ";
    constexpr char  world_str[] = "world!";
    constexpr auto  hw = fuse_strings( hello_str, world_str );

    cout << initialize_test.data() << endl;
    cout << hw.data() << endl;
}
Run Code Online (Sandbox Code Playgroud)

有一些细微之处需要注意.

  • 您的声明const(expr) char str[] = "Whatever";必须使用[]而不是*因此编译器将您的对象识别为内置数组,而不是指向运行时长度的未知(固定)内存的指针.
  • 由于内置数组不能用作返回类型,因此必须使用它std::array作为替代.问题是当您必须将结果用于以后的合并时.一个std::array对象必须具有内置阵列式合适的可公开获得的非静态数据成员,但成员的名字未在标准中规定,可能是不相符的.因此,您必须创建一个std::array类似于工作的正式避免黑客攻击.
  • 您不能将相同的代码用于常规数组连接和字符串连接.字符串是char最后一个元素必须是的数组'\0'.NUL从字符串读取时必须跳过这些值,但在写入字符串时添加这些值.这就是我的代码中出现奇数1和2的原因.对于一般数组连接(包括非字符串连接char),必须读取每个数组中的每个元素,并且不应将任何额外元素添加到组合数组中.

哦,这是定义get_strchr:

template < std::size_t N >
constexpr
char  ce_strchr( std::size_t i, const char (&s)[N] )
{
    static_assert( N, "empty string" );
    return (i < ( N - 1 )) ? s[i] : throw "too big";
}

template < std::size_t N, std::size_t M, std::size_t ...L >
constexpr
char  ce_strchr( std::size_t i, const char (&f)[N], const char (&s)[M], const char (&...t)[L] )
{
    static_assert( N, "empty string" );
    return (i < ( N - 1 )) ? f[i] : ce_strchr(i + 1 - N, s, t...);
}

template < std::size_t I, std::size_t N, std::size_t ...M >
constexpr
char  get_strchr( const char (&f)[N], const char (&...s)[M] )
{ return ce_strchr(I, f, s...); }
Run Code Online (Sandbox Code Playgroud)

(我希望你能读到这篇文章.)


Ken*_*oom 4

在 C++0x 中,您可以执行以下操作:

template<class Container>
Container add(Container const & v1, Container const & v2){
   Container retval;
   std::copy(v1.begin(),v1.end(),std::back_inserter(retval));
   std::copy(v2.begin(),v2.end(),std::back_inserter(retval));
   return retval;
}

const std::vector<int> v1 = {1,2,3};
const std::vector<int> v2 = {4,5,6};
const std::vector<int> v3 = add(v1,v2);
Run Code Online (Sandbox Code Playgroud)

我不认为有任何方法可以为 C++98 中的 STL 容器执行此操作(v3您可以执行附加部分,但不能在 C++98 中使用v1和的初始值设定项列表v2),而且我不这样做不认为有任何方法可以对 C++0x 或 C++98 中的原始数组执行此操作。