在C++ 11中,我使用constexpr函数作为模板参数的默认值 - 它看起来像这样:
template <int value>
struct bar
{
static constexpr int get()
{
return value;
}
};
template <typename A, int value = A::get()>
struct foo
{
};
int main()
{
typedef foo<bar<0>> type;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
G ++ 4.5和4.7编译它,但Clang ++ 3.1没有.来自clang的错误消息是:
clang_test.cpp:10:35: error: non-type template argument is not a constant expression
template <typename A, int value = A::get()>
^~~~~~~~
clang_test.cpp:17:19: note: while checking a default template argument used here
typedef foo<bar<3>> type;
~~~~~~~~~^~
clang_test.cpp:10:35: note: undefined function …Run Code Online (Sandbox Code Playgroud) 我正在寻找创建一个坐标查找表,如:
int a[n][2] = {{0,1},{2,3}, ... }
Run Code Online (Sandbox Code Playgroud)
对于给定的n,在编译时创建.我开始研究constexpr,但似乎是一个函数返回a constexpr std::vector<std::array <int, 2> >不是一个选项,因为我得到:
invalid return type 'std::vector<std::array<int, 2ul> >' of constexpr function
Run Code Online (Sandbox Code Playgroud)
如何创建这样的编译时数组?
我有这个非常简单的功能,无法编译.
constexpr void func()
{
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误是:
error: invalid return type 'Run Code Online (Sandbox Code Playgroud)void' ofconstexprfunction 'constexpr void func()'constexpr void func()
在C++ 14中,void是一个文字类型[§3.9/ 10]:
类型是文字类型,如果它是:
- 无效; 要么
- 标量类型; 要么
- 参考类型; 要么
- 一个文字类型的数组; 要么
- 具有以下所有属性的类类型(第9节):
- 它有一个简单的析构函数,
- 它是聚合类型(8.5.1)或至少有一个
constexpr构造函数或构造函数模板,它不是复制或移动构造函数,并且- 它的所有非静态数据成员和基类都是非易失性文字类型.
有人能解释为什么这是无效的吗?
我有以下代码:
static constexpr const char*const myString = "myString";
Run Code Online (Sandbox Code Playgroud)
你能解释一下有什么区别:
static const char*const myString = "myString";
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们与constexpr有什么新鲜事?
我似乎无法理解为什么下面的类型为const int的代码编译:
int main()
{
using T = int;
const T x = 1;
auto lam = [] (T p) { return x+p; };
}
$ clang++ -c lambda1.cpp -std=c++11
$
Run Code Online (Sandbox Code Playgroud)
而这个类型为const double的那个不是:
int main()
{
using T = double;
const T x = 1.0;
auto lam = [] (T p) { return x+p; };
}
$ clang++ -c lambda2.cpp -std=c++11
lambda1.cpp:5:32: error: variable 'x' cannot be implicitly captured in a lambda with no capture-default specified
auto lam = [] …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 int vv(int x) {return x;}
constexpr int & rr(int & x) {return x;}
constexpr int rv(int & x) {return x;}
constexpr struct S {
int x {0};
template<typename F> constexpr S(F f) {x = f(x) + 1; x = f(x) + 1;}
} s(rv); // s.x is 1 if function rv is used, 2 otherwise.
static_assert(s.x == 2, "");
Run Code Online (Sandbox Code Playgroud)
它只是rv在构造函数中使用时产生意外结果的函数.如果vv或者rr被传递,那么s.x就像预期的那样是2.
我注意到GCC 5.4.1 ARM上的行为,并且它似乎在支持C++ 14的所有GCC版本中都是相同的.Clang在所有情况下都给出了2的预期结果.GCC和Clang都没有启用Wall和Wextra的任何警告.
这个例子是有效的C++ 14和GCC中的错误吗?我阅读了标准中对常量表达式的限制列表,看不出任何明显的违反,但我不确定我是否理解所有技术细节.
我可以在编译时检测"函数参数" 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()等.
#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) 从 C++20 开始,我们可以有:
constexpr bool is_little_endian = std::endian::native == std::endian::little;
Run Code Online (Sandbox Code Playgroud)
如果可用,我希望有执行此操作的代码,否则执行运行时检测。这可能吗?
也许代码看起来像:
template<bool b = std_endian_exists_v> constexpr bool is_little_endian;
template<> constexpr bool is_little_endian<true> = std::endian::native == std::endian::little;
template<> constexpr bool is_little_endian<false> = runtime_detection();
Run Code Online (Sandbox Code Playgroud)
我知道__cplusplus通过预处理器进行测试是可能的,但是 C++20 中的编译器阶段在各个阶段都支持,因此这在任一方向都不是可靠的指标。
c++ ×10
constexpr ×10
c++11 ×6
c++14 ×2
gcc ×2
lambda ×2
c++20 ×1
clang ×1
const ×1
endianness ×1
g++ ×1
optimization ×1
return-type ×1