C++ 静态断言在使用concontint const时失败。constinit、constinit const、constexpr、const、nonconst变量中的混淆
我有一个关于编译时函数的问题。我理解静态断言应该只与类型一起工作,这些类型可以在编译时进行计算。因此,它不适用于std::string(目前,gcc10中不支持constexpr std::string),但适用于std::array(当我在编译时知道大小时)。我从Jason Turner看C++每周,所以这个片段来自这一集。 代码如下:C++ 静态断言在使用concontint const时失败。constinit、constinit const、constexpr、const、nonconst变量中的混淆,c++,constexpr,c++20,constinit,C++,Constexpr,C++20,Constinit,我有一个关于编译时函数的问题。我理解静态断言应该只与类型一起工作,这些类型可以在编译时进行计算。因此,它不适用于std::string(目前,gcc10中不支持constexpr std::string),但适用于std::array(当我在编译时知道大小时)。我从Jason Turner看C++每周,所以这个片段来自这一集。 代码如下: #包括) 映射初始化为continitvaribale。现在,Continit保证表达式是零初始化的或常量初始化的。我用常量初始化,所以根据这个变量在编译时应
#包括)
映射初始化为continitvaribale。现在,Continit保证表达式是零初始化的或常量初始化的。我用常量初始化,所以根据这个变量在编译时应该是已知的(将静态变量的初始值设置为编译时常量),但它并不意味着常量,所以我们有编译时非常量变量,这个静态断言不能工作
Map被初始化为consnit const变量。现在我们有了编译时常量变量,但静态断言拒绝工作。静态断言需要bool()类型的上下文转换常量表达式,它是T类型的转换常量表达式,是隐式转换为T类型的表达式,其中转换的表达式是常量表达式为什么这不起作用?
根据cppInsights,编译器生成的代码与constint const和constexpr相同
Map被初始化为constint const
变量。现在我们有了编译时常量变量,但是static\u assert
拒绝工作
第二种主张与第一种主张不同。我们没有编译时常量变量,因此static\u assert
不起作用
constinit
不会使您的变量成为constepr
变量,它只保证您具有恒定的初始化(因此命名为constinit
)。事实上,constant
甚至并不意味着const
:
continit std::mutex m;
是对constinit
的有效且激励性的使用,并且仍然允许我锁定和解锁m
拥有constexpr
变量的唯一方法是声明您的变量constexpr
(为声明的const
整数类型保留了一个不幸的遗留部分,这里不适用)。如果您想拥有constexpr
映射,则需要声明映射constexpr
映射已初始化为constint const变量。。。但是静态断言拒绝工作。。。为什么这不起作用
正如您所观察到的,static\u assert
需要在编译时知道表达式
但是,const
只意味着逻辑常量,并不意味着该值在编译时已知(忽略使用常量表达式初始化的常量整数值的情况)
类似地,continit
仅表示静态初始化;同样,这并不意味着该值在编译时已知
从你问题的措辞来看,我猜你是在期待:
const
+constint
-->constepr
但事实并非如此。如果您希望映射在编译时可用(即在静态断言
中),则需要将其设置为constexpr
)。您试图从错误的角度解决问题。您会看到一个声明为constint const
的变量。您认为,由于对象是不可修改的,并且由常量表达式初始化,这意味着对象是常量表达式
不是
编译器是否知道其值?绝对地但“常量表达式”并不是这样定义的
有些东西是一个恒定的表达式,因为标准说它是。声明的变量continit
不是常量表达式,因为规则没有说明它是常量表达式。声明的变量const
不是常量表达式,因为规则没有说明它是常量表达式(整数的某些情况除外,它早于constepr
)。对于这两种标记的使用没有特别的规定
如果变量声明为constexpr
(或其中一个const
整数异常),则该变量为常量表达式。并且只有常量表达式才能出现在static\u assert
中
这是规定
而且没有理由使用constint const
这种特殊情况,因为如果您想要一个常量表达式。。。您可以编写constexpr
。毕竟,您可能在某个模板代码中,有人给了您一个恰好是const
的T
,然后您在某处创建了一个constint
变量。你没有要求它是一个恒定的表达;您只需要一个静态初始化的变量。恰好是const
的类型只是偶然
当然,编译器可以利用这些知识自由地进行各种特殊的优化。但这与编译器被允许做什么无关;这是关于语言的意思。如果你想从这个声明中得到特别的意义,你应该说得对。我觉得“混乱”有点强烈。“混乱”怎么样?这仍然保留了头韵,如果你喜欢这类东西:)离题,但是仅仅使用std::mutex m(在全局范围内,假设在构造其他静态时不使用它)有问题吗?@nosenseal没有。constinit
唯一做的事情是强制执行的初始化是常量初始化。它不会改变初始化是否为常量初始化<代码>标准::互斥m代码>已经做了c
#include <array>
#include <algorithm>
template<typename Key, typename Value, std::size_t Size>
struct Map final
{
std::array<std::pair<Key, Value>, Size> _data;
[[nodiscard]] constexpr Value getMappedKey(const Key& aKey) const
{
const auto mapIterator = std::ranges::find_if(_data, [&aKey](const auto& pair){ return pair.first == aKey;});
if(mapIterator != _data.end())
{
return mapIterator->second;
}
else
{
throw std::out_of_range("Key is not in the map");
}
}
};
enum class OurEnum
{
OUR_VALUE,
OUR_VALUE2,
OUR_VALUE3
};
enum class TheirEnum
{
THEIR_VALUE,
THEIR_VALUE2,
THEIR_VALUE3
};
// This Fails non constant variable of course
/*
Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// This fails, it is const, but this does not guarentee that it will be created in compile time
/*
const Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// This works
/*
constexpr Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
//How come this does not work? Oh i see, missing const because constinit does not apply constness
/*
constinit Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
*/
// Okay, I added const specifier but still this makes static_assert fail because of non-constant condition
// Why?
constinit const Map<OurEnum, TheirEnum, 2> enumsConverter =
{
{
{{OurEnum::OUR_VALUE, TheirEnum::THEIR_VALUE},
{OurEnum::OUR_VALUE2, TheirEnum::THEIR_VALUE2}}
}
};
int main()
{
static_assert(enumsConverter.getMappedKey(OurEnum::OUR_VALUE) == TheirEnum::THEIR_VALUE);
}