【问题标题】:Cannot declare static constexpr char []无法声明静态 constexpr char []
【发布时间】:2018-01-12 04:29:46
【问题描述】:

我已阅读与此问题相关的所有答案,但老实说,我不确定我是否完全理解解决方案。我正在使用 C++11。

可以说我真的很想声明像static constexpr char value[] = "foo" 这样的东西。

如果我使用 NetBeans/TDM_MINGW,我会收到一个错误,我想这是一个链接错误报告undefined reference to "variable_name"

在 MS VS 2015 中尝试相同的代码我得到 “表达式未计算为常数”

一个简单的static constexpr char * 解决了这个问题,但我失去了使用像sizeof 这样的表达式的能力。

简单而直接的问题(如果可能的话直接回答):

  1. 有没有办法在struct/class内声明一个static constexpr char []
  2. 如果 1) 为假,是否有最干净的解决方案来克服这个问题? static constexpr char *????
  3. 或者旧的 static const char [] 仍然是这种情况下的最佳方法?
  4. 我测试了一个可行但远非“干净”的解决方案static constexpr array<char,50> getConstExpr(){ return array<char,50> {"Hell"} }。它工作正常,但我必须声明字符的大小std::array :(

【问题讨论】:

  • hmm,使用 mingw64 (4.9.2) 和相同版本的 gcc 进行测试,该行有效。有限的 c++11 支持有问题吗?你能参考你读过的东西吗?仅自 C++14 起支持静态 constexpr 成员变量

标签: c++ arrays c++11 static constexpr


【解决方案1】:

1) 有没有办法在struct/class 中声明static constexpr char []

是的;很简单。

以下是一个完整的工作示例

struct bar
 { static constexpr char value[] = "foo"; };

constexpr char bar::value[];

int main ()
 {
   std::cout << bar::value << std::endl; // print foo
 }

我想你忘记了bar::value[] 行。

2) 如果 1) 为假,是否有最干净的解决方案来克服这个问题static constexpr char * ????

不适用。

3) 还是旧的static const char [] 仍然是这种情况下的最佳方法?

取决于你要解决的问题;但通常我建议避免使用 C 样式的数组并使用新的 C++11 std::array

4) 我已经测试了一个可行但远非“干净”的解决方案 [...] 它工作正常,但我必须声明 char std::array 的大小 :(

我建议你一个解决方案(不幸的是从 C++14 开始工作,但制作 C++11 版本并不太难)从作为参数传递的"Hell" 中检测正确的大小。

注意使用std::make_index_sequencestd::index_sequence 将单个字符从char[] 变量传递到std::array

template <std::size_t Dim, std::size_t ... Is>
constexpr std::array<char, Dim> gceH (char const (&str)[Dim],
                                      std::index_sequence<Is...> const &)
 { return { { str[Is]... } }; }

template <std::size_t Dim>
constexpr std::array<char, Dim> getConstExpr (char const (&str)[Dim])
 { return gceH(str, std::make_index_sequence<Dim>{}); }

int main ()
 {
   constexpr auto f = getConstExpr("Hell");

   static_assert( 5U == f.size(), "!" );
 }

-- 编辑--

按照 Swift 的建议(谢谢!)使用模板类型,而不是 char,将 getConstExpr() 转换为更灵活的函数。

所以getConstExpr()和辅助函数(gceH())可以写成如下

template <typename T, std::size_t Dim, std::size_t ... Is>
constexpr std::array<T, Dim> gceH (T const (&str)[Dim],
                                   std::index_sequence<Is...> const &)
 { return { { str[Is]... } }; }

template <typename T, std::size_t Dim>
constexpr std::array<T, Dim> getConstExpr (T const (&str)[Dim])
 { return gceH(str, std::make_index_sequence<Dim>{}); }

【讨论】:

  • 最好把 char - 数组元素的类型 - 也作为模板的参数,不允许重用模板吗?
  • 感谢您的客观回答@max66。我确实忘记在类范围之外声明它。很高兴有你在。
  • @Swift - 为什么不呢?根据您的建议修改了答案。
  • @JacintoResende - 根据 Swift 的建议改进了答案
  • 在 C++17 中,不再需要在类范围之外声明它。 MS VS Community 2017 确实支持它并且免费供个人使用。在 Linux 上,clang 5.0 版也支持它。
【解决方案2】:

如果你想避免使用 C 风格的数组,还有一个使用 std::string_view... 的 C++17 解决方案,它更简单。 ;)

这是下面代码的perm-link

#include <iostream>
#include <string_view>

int main ()
{
    constexpr std::string_view foo ( "Hell" );
    static_assert ( 4U == foo.size (), "!" );

    std::cout << "Done";
    return EXIT_SUCCESS;
}

【讨论】:

    【解决方案3】:

    从 C++17 开始,您不需要做任何特别的事情,因为 static constexpr 成员变量隐含为 inline

    以下将起作用:

    #include <iostream>
    
    struct S
    {
        static constexpr char value[] = "Meow!\n";
    };
    
    int main()
    {
        std::cout << S::value;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      相关资源
      最近更新 更多