下面,您将找到一个用于CRC32计算的constexpr字符串文字.
我不得不重新解释字符串文字字符char来unsigned char.因为reinterpret_cast在constexpr函数中不可用,所以解决方法是手动的两个补码的小实用函数,但我对它有点失望.
处理这种操作是否存在更优雅的解决方案?
#include <iostream>
class Crc32Gen {
uint32_t m_[256] {};
static constexpr unsigned char reinterpret_cast_schar_to_uchar( char v ) {
return v>=0 ? v : ~(v-1);
}
public:
// algorithm from http://create.stephan-brumme.com/crc32/#sarwate
constexpr Crc32Gen() {
constexpr uint32_t polynomial = 0xEDB88320;
for (unsigned int i = 0; i <= 0xFF; i++) {
uint32_t crc = i;
for (unsigned int j = 0; j < 8; j++)
crc = (crc >> 1) ^ (-int(crc & …Run Code Online (Sandbox Code Playgroud) 我认为在C++ 14中,从constexpr中删除了更多限制.但根据N3797 7.1.5 3-punct:
contexpr函数shal的定义满足以下约束:
我知道为什么静态,线程存储持续时间变量是不允许的,但我没有看到任何理由,为什么只允许定义一个文字类型的变量?
或者我不明白标准.
我不确定,但是根据标准的跟随错误应该创建,即使是C++ 14:
struct point{
constexpr point(): x(0), y(0){}
constexpr point(int x_, int y_): x(x_),y(y_){}
constexpr int hypot()const { return x*x + y*y; }
int x,y;
};
constexpr int hypot(int x, int y) {
point p{x,y}; //error, because p - is not literal type.
return p.hypot();
}
// error, because return type …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
constexpr unsigned f(unsigned x)
{
while (x & 1) x *= 3;
return x;
}
int main()
{
char a[f(2)];
char b[f(1)];
}
Run Code Online (Sandbox Code Playgroud)
如果不明显:对于奇数整数x,函数f永远不会终止.
当我用coliru上的clang编译上面的程序时,b似乎是一个VLA,但不是a:
warning: variable length arrays are a C99 feature [-Wvla-extension]
char b[f(1)];
Run Code Online (Sandbox Code Playgroud)
是否存在明确定义的限制,编译器决定停止对常量表达式的求值?或者,对于符合标准的编译器来说,进入无限循环会是完美的吗?是否会f(1)产生UB?
评估编译程序所需的精确最小值-fconstexpr-steps=和-ftemplate-depth=参数的最佳方法是什么?
我目前所做的是对价值的二分法.但是对于真实世界模板加载的程序,它变得非常长,甚至在值的上限上是对数的.
有-v选项-ftime-report,但是即使它们的输出也没有给出关于实际使用的最大模板深度和在评估常量表达式时实际传递的步骤数的任何所需信息.
我有以下代码编译旧的gcc,但不是版本6(与-std = c ++ 1z一起使用).Clang也反对它,说对象val没有正确的联系.我不明白其中的区别.是不是指针类型的constexpr变量应该或多或少透明地工作?是否有一些我在语法中缺少的东西可以让它工作?或者这违反了标准的某些部分?
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
static constexpr t_voidfn val = &fn;
s<val> x;
}
Run Code Online (Sandbox Code Playgroud)
另一方面,这个工作.
typedef void(*t_voidfn)();
template <t_voidfn> struct s {};
void fn() {
s<&fn> x;
}
Run Code Online (Sandbox Code Playgroud) 考虑一个例子:
template <void (*Foo)()>
struct S {
};
int main() {
struct A {
static void x() { }
};
S<&A::x> s;
}
Run Code Online (Sandbox Code Playgroud)
代码在clang中编译,gcc认为x没有链接...对于非常类似的例子,只是在使用lambda表达式时:
template <void (*Foo)()>
struct S {
};
int main() {
auto lambda = []{};
S<+lambda> s;
}
Run Code Online (Sandbox Code Playgroud)
gcc和clang都同意不编译代码:根据gcc,由unary +返回的函数没有链接,相反,clang状态表示对该函数的强制转换操作符未声明为constexpr.是否有任何理由不允许lambda强制转换为在constexpr上下文中使用的函数指针?
查找编译器和现场演示产生的以下错误:
gcc:
prog.cc:7:14:错误:'main():::: _ FUN'不是类型'void(*)()'的有效模板参数,因为'static constexpr void main():::: _ FUN( )'没有联系
prog.cc:7:8:注意:非constexpr函数'operator void(*)()'不能用于常量表达式
根据这个答案,显然没有充分的理由说明为什么不允许结构化绑定是constexpr,但标准仍然禁止它.但是,在这种情况下,是否应该禁止在constexpr函数中使用结构化绑定?考虑一个简单的片段:
#include <utility>
constexpr int foo(std::pair<int, int> p) {
auto [a, b] = p;
return a;
}
int main() {
constexpr int a = foo({1, 2});
static_assert(a == 1);
}
Run Code Online (Sandbox Code Playgroud)
我可以在编译时检测"函数参数" 1是否是编译时常量?
例如,一个函数print(int i)可以"constant 5"在被调用时打印,print(5)但"non-constant 5"如果被调用为print(i)where,i则是一些非常量变量.特别是,在"is constant"分支中,我应该能够将其i视为constexpr,包括将其用于模板参数等.
宏技巧,模板元编程和SFINAE技巧都可以.理想情况下它是可移植的,但是编译器特定的解决方案总比没有好.
如果存在"错误否定"则可以 - 即,如果常量值有时被检测为非常数(例如,禁用某些优化时).
如果解决方案可以检测到常量值何时间接传递给函数(例如,当一个常量值传递给调用的中间函数print并且随后内联将常量暴露给print)时,可以获得奖励积分.最后一种行为显然取决于优化.
如果它自然延伸到多个参数,则可获得双倍奖励
如果一个人可以使用和不带constexpr参数重载函数的版本,这可能是直截了当的,但你不能.
1我在这里引用"函数参数",因为解决方案并不严格要求在函数内(或在具有特殊参数的调用者/被调用者边界)检测此状态 - 它只需要像函数一样出现给调用者但是可以使用宏或其他技巧,如静态对象operator()等.
为什么emplace_back要引用需要定义的成员?emplace_back(integer literal)和之间有什么区别emplace_back(static constexpr integer member)?
如果我切换到C++ 17,它编译得很好.我发现在C++ 17中,静态constexpr数据成员是隐式内联的.这是否意味着编译器隐式为它们创建定义?
示例代码:
class base {
int n;
public:
base(int n):n(n) {}
};
struct base_trait {
static constexpr int n = 1;
};
int main(void) {
vector<base> v;
v.emplace_back(1); // ok
v.emplace_back(base_trait::n); // link error with -std=c++14, ok with -std=c++17
return 0;
}
Run Code Online (Sandbox Code Playgroud) #include <cstddef>
template<typename... Types>
constexpr std::size_t getArgCount(Types&&...) noexcept
{
return sizeof...(Types);
}
struct A
{
int n;
void f()
{
static_assert(getArgCount(n) > 0); // not ok, why?
}
};
int main()
{
int n;
static_assert(getArgCount(n) > 0); // ok
}
Run Code Online (Sandbox Code Playgroud)
为什么在编译时无法获得模板函数的参数计数?
错误信息:
1>test.cpp
1>test.cpp(17,45): error C2131: expression did not evaluate to a constant
1>test.cpp(17,42): message : failure was caused by a read of a variable outside its lifetime
1>test.cpp(17,42): message : see usage of 'this'
Run Code Online (Sandbox Code Playgroud)