C++11:使用另一个constexpr字符数组初始化constexpr字符数组

5

我想用另一个constexpr char []成员初始化constexpr char[]成员。在C++11或以上版本中是否可以实现?

#include <iostream>

struct Base {
 static constexpr char ValueOne[] = "One";
 static constexpr char ValueTwo[] = "Two";
};

template <typename T>
struct ValueOneHolder {
  static constexpr char Value[] = T::ValueOne; // << How can one initialize this?
};

int main() {
  std::cout << ValueOneHolder<Base>::Value << std::endl;
  return 0;
}

使用std::array代替? - Ben Voigt
另一个选择可能是使用constexpr引用,除非你需要这两个数组的唯一地址。 - Ben Voigt
2个回答

2
我想用另一个constexpr char []成员来初始化constexpr char[]成员。在C++11或更高版本中是否可以实现?
从C++14开始,您可以使用std::make_index_sequencestd::index_sequence
如果您可以在ValueOneHolder专业化中工作,首先可以开发一个constexpr函数,该函数给定C样式数组,返回数组的大小。
template <typename T, std::size_t N>
constexpr std::size_t getDim (T const (&)[N])
 { return N; }

接下来,您可以声明一个ValueOneHolder,添加第二个模板参数,其默认值是与T::ValueOne对应的索引序列。"最初的回答"。
template <typename T,
          typename = std::make_index_sequence<getDim(T::ValueOne)>>
struct ValueOneHolder;

最后是简单的部分:带初始化的偏特化
template <typename T, std::size_t ... Is>
struct ValueOneHolder<T, std::index_sequence<Is...>>
 { static constexpr char Value[] = { T::ValueOne[Is] ... }; };

不要忘记在结构体之外添加以下行。最初的回答。
template <typename T, std::size_t ... Is>
constexpr char ValueOneHolder<T, std::index_sequence<Is...>>::Value[];

以下是一个完整的C++14编译示例,即"最初的回答"。
#include <utility>
#include <iostream>

struct Base
 {
   static constexpr char ValueOne[] = "One";
   static constexpr char ValueTwo[] = "Two";
 };

template <typename T, std::size_t N>
constexpr std::size_t getDim (T const (&)[N])
 { return N; }

template <typename T,
          typename = std::make_index_sequence<getDim(T::ValueOne)>>
struct ValueOneHolder;

template <typename T, std::size_t ... Is>
struct ValueOneHolder<T, std::index_sequence<Is...>>
 { static constexpr char Value[] = { T::ValueOne[Is] ... }; };

template <typename T, std::size_t ... Is>
constexpr char ValueOneHolder<T, std::index_sequence<Is...>>::Value[];

int main()
 {
   std::cout << ValueOneHolder<Base>::Value << std::endl;
 }

如果你需要C++11,你可以开发一个替代std::make_index_sequencestd::index_sequence的工具。


我怀疑是否有人能够替代index_sequence - 它基于一个神奇的内部特性。 - hutorny
@hutorny - std::index_sequence的替代品很简单;它是std::make_index_sequence(或更好的是std::make_integer_sequence)的替代品,后者更复杂一些,但并不是太难。真正的问题在于,std::make_integer_sequence应该(标准规定)是一个std::integer_sequence,而不仅仅是从中继承的东西。而这个问题我不知道如何在C++11中实现(但这个问题只需要对ValueOneHolder的代码进行一点改变即可)。 - max66

2
在这个特定的例子中,您可以将Value声明为以下内容:
template <typename T>
struct ValueOneHolder {
  static constexpr auto Value = T::ValueOne; // << How can one initialize this?
};

请注意,除非您切换到-std=c++17或在源文件中添加以下行,否则GCC将无法链接此示例。
constexpr char Base::ValueOne[];
constexpr char Base::ValueTwo[];

使用C++14,也可以制作一个constexpr字符串(或其子字符串)的constexpr副本,如下面的示例所示:

template<typename CharT, size_t Size>
struct basic_cestring {
    using value_type = CharT;
    template<size_t... I> constexpr
    basic_cestring(const char* str, index_sequence<I...>)
      : _data{str[I]...} {}
    inline constexpr operator const CharT* () const { return _data; }
    const CharT _data[Size + 1];
};

template<size_t Size>
struct cestring : public basic_cestring<char, Size>  {
    using index = make_index_sequence<Size>;
    constexpr cestring(const char* str)
    : basic_cestring<char, Size>(str, index{}) {}
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接