繁体   English   中英

使用 constexpr 函数的结果作为模板参数(clang vs gcc)

[英]using result of constexpr function as a template parameter (clang vs gcc)

请看一下下面的代码,抱歉有点冗长,但我已尽力用最少的示例重现问题(还有它的实时副本)。 在那里我基本上有一个元函数,它返回字符串文字的大小,以及包装它的 constexpr 函数。 然后,当我在模板参数中调用这些函数时,gcc (5.4, 6.2) 对此很满意,但是在strsize(s)测试主体中,带有“非类型模板参数不是常量表达式”的 clang (3.8, 3.9) barfs . 如果我用str_size<S>替换,两个编译器都会很高兴。 所以问题是:

  1. 这是clang的问题还是我的代码的问题?

  2. 使用 constexpr 函数使其在 clang 和 gcc 上编译的方法是什么?

     template<size_t N> using string_literal_t = char[N]; template<class T> struct StrSize; ///< metafunction to get the size of string literal alikes /// specialize StrSize for string literals template<size_t N> struct StrSize <string_literal_t<N>>{ static constexpr size_t value = N-1; }; /// template variable, just for convenience template <class T> constexpr size_t str_size = StrSize<T>::value; /// now do the same but with constexpr function template<class T> constexpr auto strsize(const T&) noexcept-> decltype(str_size<T>) { return str_size<T>; } template<class S, size_t... Is> constexpr auto test_helper(const S& s, index_sequence<Is...>) noexcept-> array<char, str_size<S>> { return {s[Is]...}; } template<class S> constexpr auto test(const S& s) noexcept-> decltype(auto) { // return test_helper(s, make_index_sequence<str_size<S>>{}); // this work in both clang and gcc return test_helper(s, make_index_sequence<strsize(s)>{}); // this works only in gcc } auto main(int argc, char *argv[])-> int { static_assert(strsize("qwe") == 3, ""); static_assert(noexcept(test("qwe")) == true, ""); return 0; }

Clang 在这里是正确的。 问题出在代码和 GCC 中,它错误地接受了它。 这在 GCC 10 中已修复: https : //gcc.gnu.org/bugzilla/show_bug.cgi?id=66477

根据标准expr.const#5.12

表达式 E 是核心常量表达式,除非 E 的计算遵循抽象机的规则,将计算以下之一: ... 引用变量或引用类型数据成员的 id 表达式,除非引用有一个前面的初始化,或者

  • 它可用于常量表达式或
  • 它的生命周期开始于 E 的计算; 并且这里编译器无法验证test(const S& s)中引用的有效性。

实际上这里有一篇不错的文章可以阅读: https : //brevzin.github.io/c++/2020/02/05/constexpr-array-size/

至于你的另一个问题:

使用 constexpr 函数使其在 clang 和 gcc 上编译的方法是什么?

您可以使用按值传递的std::array替换引用:

#include <array>
using namespace std;

template<class T> struct StrSize;

template<size_t N>
struct StrSize <array<char,N>>{ static constexpr size_t value = N-1; };

template <class T>
constexpr size_t str_size = StrSize<T>::value;

template<class T>
constexpr auto strsize(const T&) noexcept-> decltype(str_size<T>) {
   return str_size<T>;
}

template<class S, size_t... Is>
constexpr auto test_helper(const S& s, index_sequence<Is...>) noexcept-> array<char, str_size<S>> {
   return {s[Is]...};
}

constexpr auto test(array<char,4> s) noexcept-> decltype(auto) {
   return test_helper(s, make_index_sequence<strsize(s)>{});
}

int main() {
   static_assert(noexcept(test({"qwe"})) == true, "");
}

演示: https : //gcc.godbolt.org/z/G8zof38b1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM