如何在C++11中初始化std::vector<std::string>的静态constexpr成员?

3

我尝试在我的类Foo中初始化一个static constexpr std::vectorstd::string,以后我会使用其元素的地址。

class Foo {
public:
  static constexpr std::vector<std::string> a = {"a", "bc", "232"}; // not working, constexpr variable not literal ....
  const std::vector<std::string> a = {"a", "bc", "232"}; // this works
}

使用C++11,谢谢。


1
我认为你不能这样做。如果你提供了变量使用的详细信息,你可能会得到一些有用的反馈。要使一个变量成为“constexpr”,它必须满足LiteralType的要求。std::vector<std::string>不符合LiteralType的要求。 - R Sahu
std::vector(或std::string)没有constexpr构造函数,因此我看不到初始化constexpr std::vector<std::string>的方法。 - max66
我可以接受使用const代替constexpr,但有点奇怪的是没有其他方法可以实现这个。 - TMS
@TMS 为什么这让你感到惊讶?vectorstring包含的数据只能在运行时动态分配,无法在编译时分配。 - Remy Lebeau
@RemyLebeau,哦,也许在这里用std::array替换vector更好。但你是对的,vector在这里不是一个好的例子。 - TMS
1个回答

4
我可以理解您愿意使用const而不是constexpr。但有一种更好的方法来创建比什么都没有的constexpr静态成员,它使用std::array而不是std::vector,并且再次使用std::array而不是std::string。
不幸的是,您正在使用C++11,因此没有std::index_sequence/std::make_index_sequence(从C++14开始提供),但我在下面的完整示例中添加了一个C++11替代品。
如果您知道想要在constexpr成员中使用的字符串的更高限制,例如9(在您的示例中为3),则可以定义一个fakeString类型,如下所示:
using fakeString = std::array<char, 10u>;

请注意,std::array 的大小为最大长度加一(再加上最后的零)。

现在您可以定义如下的 foo

struct foo
 {
   static constexpr std::array<fakeString, 3u> a
    {{ fs("a"), fs("bc"), fs("232") }};
 };

constexpr std::array<fakeString, 3u> foo::a;

其中,fs() 是一个 constexpr 函数,它接受一个 C 风格的 char 数组,并返回一个 fakeString。它使用了一个辅助函数 fsh()

fs()fsh() 函数分别定义如下:

template <std::size_t ... Is, std::size_t N>
constexpr fakeString fsh (indexSequence<Is...> const &, char const (&s)[N])
 { return {{ s[Is]... }}; }

template <std::size_t N>
constexpr fakeString fs (char const (&s)[N])
 { return fsh(makeIndexSequence<N>{}, s); }

现在你可以按照以下方式使用foo::a
   for ( auto const & fakeS : foo::a )
      std::cout << fakeS.data() << std::endl;

请注意,您需要调用返回C风格字符串的data()方法,该字符串是char *类型的。请注意,这只是为了好玩。
以下是一个完整的C++11编译示例。
#include <array>
#include <iostream>

template <std::size_t...>
struct indexSequence
 { using type = indexSequence; };

template <typename, typename>
struct concatSequences;

template <std::size_t... S1, std::size_t... S2>
struct concatSequences<indexSequence<S1...>, indexSequence<S2...>>
   : public indexSequence<S1..., ( sizeof...(S1) + S2 )...>
 { };

template <std::size_t N>
struct makeIndexSequenceH
   : public concatSequences<
               typename makeIndexSequenceH<(N>>1)>::type,
               typename makeIndexSequenceH<N-(N>>1)>::type>::type
 { };

template<>
struct makeIndexSequenceH<0> : public indexSequence<>
 { };

template<>
struct makeIndexSequenceH<1> : public indexSequence<0>
 { };

template <std::size_t N>
using makeIndexSequence = typename makeIndexSequenceH<N>::type;

using fakeString = std::array<char, 10u>;

template <std::size_t ... Is, std::size_t N>
constexpr fakeString fsh (indexSequence<Is...> const &, char const (&s)[N])
 { return {{ s[Is]... }}; }

template <std::size_t N>
constexpr fakeString fs (char const (&s)[N])
 { return fsh(makeIndexSequence<N>{}, s); }

struct foo
 {
   static constexpr std::array<fakeString, 3u> a
    {{ fs("a"), fs("bc"), fs("232") }};
 };

constexpr std::array<fakeString, 3u> foo::a;

int main ()
 {
   for ( auto const & fakeS : foo::a )
      std::cout << fakeS.data() << std::endl;
 }

谢谢您指出 std::array 实际上是我想要的,并给了我示例。 - TMS

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