Sla*_*ava 5 c++ templates clang constexpr
请看下面的代码,抱歉有点冗长,但我尽力用最小的例子重现问题(还有它的实时副本).在那里我基本上有一个返回字符串文字大小的元函数,以及包装它的constexpr函数.然后当我在模板参数中调用这些函数时,gcc(5.4,6.2)对它很满意,但是在测试体中,clang(3.8,3.9)barfs与"非类型模板参数不是常量表达式" strsize(s)
.如果我用str_size<S>
两个编译器替换都很高兴.所以问题是:
这是clang或我的代码有问题吗?
使用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;
}
Run Code Online (Sandbox Code Playgroud)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, "");
}
Run Code Online (Sandbox Code Playgroud)
演示: https: //gcc.godbolt.org/z/G8zof38b1