我知道如下所示的模板化类型不会对编译的二进制大小产生任何影响:
template<auto value>
struct ValueHolder{};
Run Code Online (Sandbox Code Playgroud)
我正在制作一个程序,它将使用很多此类包装类型,并且我认为我不想integral_constant因为这个原因而使用 s ,因为它们有一个::value成员。我可以摆脱类似的事情:
template<typename ValHolder>
struct Deducer;
template<auto value>
struct Deducer<ValueHolder<value>> {
using Output = ValueHolder<value+1>;
};
Run Code Online (Sandbox Code Playgroud)
但这肯定需要更多的工作,所以我想确保我不会白做。请注意,我们正在谈论大量这样的值(我会解释,但我不想离题太远;我可能会得到更多关于“我应该做这个项目”的评论而不是问题!) 。
所以问题是: [static] constexpr 值在编译的二进制文件中是否采用任何大小,或者这些值是否在编译时被替换,就好像它们是按字面输入的一样?我很确定它们确实会占用二进制文件的大小,但我并不肯定。
我做了一些测试来godbolt并排查看 constexpr 与非 constexpr 数组的组装,一切看起来都与我非常相似: https: //godbolt.org/z/9hecfq
int main()
{
// Non-constexpr large array
size_t arr[0xFFFF] = {};
// Constexpr large array
constexpr size_t cArr[0xFFF] = {};
// Just to avoid unused variable optimizations / warnings
cout << arr[0] << cArr[0] << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud) 注意:我使用的是 gcc,但在 godbolt.org 上进行了测试,它也适用于 msvc,但不适用于 clang
\n我意外地发现以下简单函数在模板类中进行编译,但不能作为自由函数进行编译。有人可以解释为什么吗?
\n编译正常:
\n template <typename T = void>\n class A\n {\n public:\n static constexpr std::string f()\n {\n return std::string();\n }\n }\nRun Code Online (Sandbox Code Playgroud)\n不编译:
\n constexpr std::string f()\n {\n return std::string();\n }\nRun Code Online (Sandbox Code Playgroud)\n抛出错误:
\nerror: invalid return type \xe2\x80\x98std::string\xe2\x80\x99 {aka \xe2\x80\x98std::__cxx11::basic_string<char>\xe2\x80\x99} of \xe2\x80\x98constexpr\xe2\x80\x99 function ...\n...\n/usr/include/c++/9/bits/basic_string.h:77:11: note: \xe2\x80\x98std::__cxx11::basic_string<char>\xe2\x80\x99 is not literal because:\n 77 | class basic_string\n | ^~~~~~~~~~~~\n/usr/include/c++/9/bits/basic_string.h:77:11: note: \xe2\x80\x98std::__cxx11::basic_string<char>\xe2\x80\x99 has a non-trivial destructor\nRun Code Online (Sandbox Code Playgroud)\n 我试图找出限制constexprcpp11/14 中的限制。我在CPP14-5.19-4中发现了一些使用要求:
\n\n常量表达式可以是泛左值核心常量表达式\n其值引用具有静态存储持续时间的对象或函数\n,也可以是纯右值核心常量表达式\n其值是对象\n其中,对于该对象及其子对象:
\n\n
\n- ...
\n- 如果对象或子对象是指针类型,则它包含具有静态存储持续时间的另一个对象的地址、此类对象末尾的地址 (5.7)、函数的地址或空指针值。
\n
我已经对涉及地址运算符的表达式运行了一些测试(代码如下所示)&,以确保上面引用的标准语句的正确性。
简而言之,我试图获取全局int变量的地址global_var,它是一个具有静态存储持续时间的对象(如果我没有想错的话),一切都按照标准指出的那样工作。但是,令我困惑的是,当我尝试分配另一个指针类型对象(global_var_addr1在代码中)时,它存储了同一对象的地址global_var时,程序将无法编译。海湾合作委员会说:
\n\n错误:\xe2\x80\x98global_var_addr1\xe2\x80\x99 的值在常量表达式中不可用
\n
\n注意:\xe2\x80\x98global_var_addr1\xe2\x80\x99 未声明\xe2\x80\x98constexpr\xe2 \x80\x99
,而 Clang-Tidy 说:
\n\n\n错误:constexpr 变量“x2”必须由常量表达式初始化 [clang-diagnostic-error]
\n
\n注意:在常量表达式中不允许读取非 constexpr 变量 \'global_var_addr1\'
我不知道为什么,我错过了什么吗?
\n1. 为什么在常量表达式中,我不能使用标准规定的包含具有静态存储持续时间的对象的地址的指针类型对象?
\n 2. 为什么在与 (1) 相同的上下文中,当对象是auto?
欢迎任何建议,提前致谢!
\n代码:
\nconst …Run Code Online (Sandbox Code Playgroud) 我有这个简单的代码,我想向这个函数发送两个参数,一个是“i”,另一个是“n”,当尝试在等于“n”的情况下切换“i”时,我失败了,因为他说'n'不是常量表达式,我读到了这个问题,我想找到一种方法使'n'是常量表达式。这是函数:
float east_coefficient(int i, int n){
switch(i){
case 1:
return 0;
break;
case n:
return 0;
break;
default:
return 1;
}
}
Run Code Online (Sandbox Code Playgroud)
这是主要功能:
int main(){
int i, x;
const int n = 5;
x = east_coefficient(i, n);
cout << x;
}
Run Code Online (Sandbox Code Playgroud) (接着这个问题:)
void foo() {
constexpr const auto my_lambda = [](int z) { return z+1; };
}
Run Code Online (Sandbox Code Playgroud)
显然,my_lambda“不是静态的”。除了没有正式定义之外,在什么意义上它不是静态的?为什么它不应该是隐式静态的,看看它似乎符合定义?
比较以下内容:
我在一个类中有一个静态成员,要么是const constexpr要么只是constexpr. 根据MS Docs上的解释,constexpr 意味着常量:
所有 constexpr 变量都是 const。
然而,这会在 gcc 8.4 中发出警告:
#include <iostream>
#include <string>
struct some_struct
{
static constexpr char* TAG = "hello";
void member() {
printf("printing the tag %s", TAG);
}
};
int main()
{
some_struct A;
A.member();
}
Run Code Online (Sandbox Code Playgroud)
虽然这不会:
#include <iostream>
#include <string>
struct some_struct
{
static const constexpr char* TAG = "hello";
void member() {
printf("printing the tag %s", TAG);
}
};
int main()
{
some_struct A; …Run Code Online (Sandbox Code Playgroud) consider this example:
template<typename T>
concept Iteratable = requires(T n) {
n.begin();
n.end();
};
namespace detail {
template<Iteratable T>
using subtype = std::decay_t<decltype(*(std::declval<T>().begin()))>;
template<Iteratable T>
constexpr auto deepest_subtype_recursive() {
if constexpr (Iteratable<subtype<T>>) {
return detail::deepest_subtype_recursive<subtype<T>>();
}
else {
return subtype<T>{};
}
}
}
template<Iteratable T>
using deepest_subtype = decltype(detail::deepest_subtype_recursive<T>());
Run Code Online (Sandbox Code Playgroud)
A recursive function that calls itself with the subtype, until the type in question is no longer iteratable, then that type is returned. What this enables, is to find the deepest …
int main() {\n constexpr int i = 5;\n constexpr const int *p = &i;\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n编译上面的代码后:
\ng++ main.cpp\nRun Code Online (Sandbox Code Playgroud)\n这是错误:
\n\n\nmain.cpp: 在函数 \xe2\x80\x98int main()\xe2\x80\x99: \xe2\x95\x91
\n
\n~ \xe2\x95\x91main.cpp:3:28: 错误: \xe2\x80 \x98& i\xe2\x80\x99 不是常量表达式 \xe2\x95\x91
\n~ \xe2\x95\x91 3 | constexpr const int *p = &i; \xe2\x95\x91
\n~ \xe2\x95\x91 | ^~ \xe2\x95\x91
\n~ \xe2\x95\x91 \xe2\x95\x91
这是我的 g++ 版本:
\n \xe2\x95\x91Target: x86_64-pc-linux-gnu \xe2\x95\x91 \n \xe2\x95\x91Configured with: /build/gcc/src/gcc/configure --enable-languages=c,c++,a\xe2\x95\x91\n~ \xe2\x95\x91da,fortran,go,lto,objc,obj-c++,d --enable-bootstrap --prefix=/usr --libd\xe2\x95\x91\n~ \xe2\x95\x91ir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr\xe2\x95\x91\n~ \xe2\x95\x91/share/info …Run Code Online (Sandbox Code Playgroud) 我试图了解 if constexpr 的实用程序,并想知道以这种方式使用它是否有任何实用程序。
template<bool B>
int fun()
{
if constexpr (B)
return 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这个函数是否通过使用 if constexpr 而不是常规 if 进行了根本改变?我认为性能是一样的。我对模板的理解是 if 语句的结果在编译时就已经知道,所以没有区别。
我想引入在编译时进行错误检查的强类型。对于我的 chrono 类型,我注意到当基础类型从 变为 时,文字会默默地缩小int64_t,int32_t从而导致溢出。所以我引入了显式检查。
delay_t {10s}然而,即使对于常量参数(例如无法表示的 ),在编译时也不会检查此检查。
#include <chrono>
#include <cstdint>
#include <stdexcept>
struct delay_t {
std::chrono::duration<int32_t, std::nano> value {};
constexpr explicit delay_t(std::chrono::duration<int64_t, std::nano> delay)
: value {delay}
{
if (value != delay) {
throw std::runtime_error("delay cannot be represented.");
}
};
};
auto foo(delay_t delay) -> void {}
auto main() -> int {
using namespace std::chrono_literals;
foo(delay_t {10s}); // here I want a compile time error,
// but I get a runtime error.
return …Run Code Online (Sandbox Code Playgroud)