constexpr 相关问题

constexpr是C ++ 11中引入的修饰符,它通知编译器函数或变量的值是已知的,或者可以在编译时计算。因此,它可以在不可能的地方用作常数。

C++ 常量表达式中计算阶乘时出错

以下程序使用函数fact 计算阶乘。它在运行时工作得很好,但在最新的 Visual Studio 2022 和我拥有的所有以前的版本中,对事实的持续评估失败了

回答 1 投票 0

为什么添加另一个简单的构造函数会使简单的类不再是文字类型?

只需添加 MyPair(const A& first, const B& secondary) 函数即可使“MyPair”不再是文字类型。 为什么? 模板 类 MyPair { 公众:首先...

回答 1 投票 0

当我尝试在C++编译时创建initializer_list时有些麻烦

std::initializer_list 是一个有用的工具,可以在 C++ 中初始化许多容器,当我尝试使用 C++ 模板生成算术级数时,我发现它存在一些问题。 下面是一个

回答 1 投票 0

constexpr 是否意味着内联?

考虑以下内联函数: // 内联说明符版本 #包括 #包括 内联 int f(const int x); 内联 int f(const int x) { 返回 2*x; } 整数

回答 2 投票 0

lazy 仅在“if constexpr”内需要时才评估昂贵的局部变量,而无需运行时 if-else

我必须在函数中的 5-10 个位置使用变量 v。 从分析来看,v 的初始化(相对)非常昂贵。 如何仅在需要时才初始化 v? 不幸的是它是一个引擎...

回答 1 投票 0

如何在保持 API 简单的同时加入编译时类似字符串的对象?

我正在尝试在编译时连接类似字符串的对象。在这篇文章的帮助下,我想出了这样的东西: #包括 #包括 #包括 我试图在编译时连接类似字符串的对象。在这篇文章的帮助下,我想出了这样的东西: #include <cstddef> #include <algorithm> #include <array> #include <cstring> #include <string> #include <string_view> template <std::size_t N> class ConstexprChars { private: std::array<char, N> _string; template <std::size_t S> friend class ConstexprChars; template <std::size_t S1, std::size_t S2> constexpr ConstexprChars(const std::array<char, S1> s1, const std::array<char, S2> s2) : _string() { std::copy(s1.begin(), s1.end() - 1, _string.begin()); std::copy(s2.begin(), s2.end() - 1, _string.begin() + S1 - 1); } public: constexpr ConstexprChars(const char (&str)[N]) : _string() { std::copy(&str[0], &str[0] + N, _string.begin()); } constexpr ConstexprChars(const std::array<char, N> str) : _string() { std::copy(&str[0], &str[0] + N, _string.begin()); } constexpr ConstexprChars(std::string_view str) : _string() { std::copy(str.data(), str.data() + N, _string.begin()); } template <std::size_t S> constexpr auto operator+(const ConstexprChars<S> other) const { return ConstexprChars<N + other._string.size() - 1>(_string, other._string); } [[nodiscard]] constexpr auto c_str() const { return _string.data(); } }; template <std::size_t N, std::size_t... Ns> constexpr auto cconcat_impl(const char (&first)[N], const char (&... rest)[Ns]) { if constexpr (!sizeof...(Ns)) { return ConstexprChars<N>{first}; } else { return ConstexprChars<N>{first} + cconcat_impl(rest...); } } template <std::size_t... Ns> constexpr auto cconcat(const char (&... strings)[Ns]) { return cconcat_impl(strings...); } #include <iostream> int main() { // this works; constexpr const char name[] = "Edward"; constexpr auto joined1 = cconcat("name=", name); std::cout << joined1.c_str() << std::endl; // this does not work: // constexpr std::string_view value = "42"; // essentially same as constexpr const char* // constexpr auto joined2 = cconcat("value=", value); // std::cout << joined2.c_str() << std::endl; return 0; } 但是,这仅适用于字符串文字和字符数组。有没有办法扩展其他编译时类似字符串对象的功能? 编辑: 正如@Oersted所建议的,实现这一目标的一种方法是添加这些重载和宏方案(为了简单起见,忽略了混合搭配的可能性): constexpr std::size_t cptr_size(const char* cptr) { return std::string_view{cptr}.length() + 1; } template <std::size_t N> constexpr auto make_array(const char* cptr) { std::array<char, N> arr; std::copy_n(cptr, N, arr.data()); return arr; } #define MAKEARRAY(str) make_array<cptr_size(str)>(str) template <std::size_t N, std::size_t... Ns> constexpr auto cconcat_impl(const std::array<char, N> first, const std::array<char, Ns>... rest) { if constexpr (!sizeof...(Ns)) { return ConstexprChars<N>{first}; } else { return ConstexprChars<N>{first} + cconcat_impl(rest...); } } template <std::size_t... Ns> constexpr auto cconcat(const std::array<char, Ns>... strings) { return cconcat_impl(strings...); } 那么,我们可以这样做: int main() { constexpr const char* value = "42"; constexpr auto joined2 = cconcat(MAKEARRAY("value="), MAKEARRAY(value)); std::cout << joined2.c_str() << std::endl; return 0; } 但是,这改变了 API。是否可以在保留相同 API 的同时实现这一目标?也就是说,是否可以有这个: int main() { constexpr const char* value = "42"; constexpr auto joined2 = cconcat("value=", value); std::cout << joined2.c_str() << std::endl; return 0; } 您需要将串联结果存储在编译时大小的数组中(例如std::array)。但是 std::string_view::size 是其值的一部分(而不是其类型),并且不能用于确定串联函数的结果类型。最直接的方法是定义一个 fixed_string 类模板并将大小放入其类型元数据中。类模板可以将转换运算符声明为 std::array、std::string_view 和 std::string。对于运行时串联,您需要在串联序列中提供至少一个 std::string 类的实例。如果使用 operator+ 来执行串联,语法将保持一致: template<std::array val> struct fixed_string{ using this_arr_t = std::remove_cv_t<decltype(val)>; using value_type = this_arr_t::value_type; using string_view = std::basic_string_view<value_type>; consteval static auto size() {return size(val)-!back(val);}; consteval operator std::basic_string_view<value_type>() const{return string_view{data(val), this->size()};}; constexpr operator std::basic_string<value_type>() const{return std::basic_string{ string_view{*this}};}; consteval static auto begin() {return std::begin(string_view{fixed_string{}});}; consteval static auto end() {return std::end(string_view{fixed_string{}});}; template<std::size_t N> consteval static auto arrcat(array<value_type, N> rhs) ->std::array<value_type, size() + N> { std::array<value_type, size() + N> res; std::ranges::copy(rhs, std::ranges::copy(fixed_string{}, begin(res)).second); return res; }; template<std::array rhs> consteval fixed_string<arrcat(rhs)> operator+(fixed_string<rhs>) {return {};}; private: // I would like the class empty }; template<std::array val> consteval fixed_string<val> operator""_fxstr() {return {};}; auto str = "this"_fxstr + " is a "_fxstr + "std::string"s; 为了清楚起见,我留下了很多实现细节。例如:我会从末尾删除空终止符,但人们可能想保留它。 但是 ` 提供了一种更简单的方法来零努力地实现这一目标: auto str = std::array{ "this"sv , "is"sv , "a"sv , "std::string"s } | std::views::join("_") | std::ranges::to<std::string>(); 如果输入是,则join的结果可以是constexpr。但在被收集为 string 或 vector 与 ranges::to 之前,它不会是连续的范围。 最后一点 - 正如评论中已经提到的 - 是避免定义与 Qt 等著名库中的名称相同的标识符: QObject 是与您的预期用途无关的名称,并且是抽象基类名称Qt。 总结我的评论,我实现了这个片段。是否满足您的需求: #include <algorithm> #include <array> #include <cstddef> #include <iostream> #include <string_view> namespace Details { template <size_t N> struct StringWrapper { std::array<char, N> value; std::size_t size; constexpr explicit(false) StringWrapper(const char (&str)[N]) : size(N) { std::copy_n(static_cast<const char *>(str), N, value.data()); } }; } // namespace Details template <Details::StringWrapper head, Details::StringWrapper tail> class SConcat { constexpr static std::array<char, head.size + tail.size - 1> init() { std::array<char, head.size + tail.size - 1> conc; std::copy(std::cbegin(head.value), std::cend(head.value) - 1, std::begin(conc)); std::copy(std::cbegin(tail.value), std::cend(tail.value), std::begin(conc) + head.size - 1); return conc; } static constexpr std::array<char, head.size + tail.size - 1> data = init(); public: static constexpr std::string_view as_sv() { return {data.data()}; } }; int main() { constexpr char value[] = "42"; const std::string_view conc{SConcat<"value=", value>::as_sv()}; std::cout << conc << '\n'; return static_cast<int>(conc[1] == 'a'); } 直播 我认为它可以得到显着的完善,但它给出了主要思想。 First StringWrapper 只是一种将原始字符串隐式转换为可用作 SConcat 的 CNTTP 对象的方法(因此需要 C++20)。 因此,SConcat为其声明中使用的每对字符串提供了唯一的类型,并且串联结果保存在提供存储的静态成员变量data中。 通过string_view方法最终可以得到as_sv()。 (NB1,通过删除 std::cout 部分,您可以看到编译器如何优化所有内容,然后是程序集: main: mov eax, 1 ret NB2 static_cast 只是为了消除一些误报警告。 ) 编辑:支持各种字符串文字声明的替代方案,按照 op 的要求,有点详细。 #include <algorithm> #include <array> #include <cstddef> #include <string> #include <string_view> // #define PROVEOPTIM #ifndef PROVEOPTIM #include <iostream> #endif namespace Details { constexpr std::size_t MySize(const char *str) { std::string tmp{str}; return tmp.length(); } template <std::size_t N> constexpr auto MakeArray(const char *str) { std::array<char, N + 1> arr; std::copy_n(str, N + 1, arr.data()); return arr; } } // namespace Details #define MAKEARRAY(str) Details::MakeArray<Details::MySize(str)>(str) template <std::array head, std::array tail> class SConcat { constexpr static std::array<char, head.size() + tail.size() - 1> init() { std::array<char, head.size() + tail.size() - 1> conc; std::copy(std::cbegin(head), std::cend(head) - 1, std::begin(conc)); std::copy(std::cbegin(tail), std::cend(tail), std::begin(conc) + head.size() - 1); return conc; } static constexpr std::array<char, head.size() + tail.size() - 1> data = init(); public: static constexpr std::string_view as_sv() { return {data.data()}; } }; int main() { constexpr const char *value = "42"; constexpr const char value2[] = "3.14"; const std::string_view conc{ SConcat<MAKEARRAY("value="), MAKEARRAY(value)>::as_sv()}; const std::string_view conc2{ SConcat<MAKEARRAY("value="), MAKEARRAY(value2)>::as_sv()}; #ifndef PROVEOPTIM std::cout << conc << '\n'; std::cout << conc2 << '\n'; #endif return static_cast<int>(conc[1] == 'a'); } 直播 它依赖于从指向作为 std::array 或 const char* 传递的空终止字符串的指针显式构建 const char[]。宏 MAKEARRAY 将两个操作合并为一个:获取大小作为编译时常量,并从用于获取大小的同一源复制数据。 显然,如果“字符串”不是以 null 结尾,则结果是未定义的。

回答 2 投票 0

如何避免在加入编译时 string_views 时指定编译时大小?

我正在尝试在编译时连接 string_views。在这篇文章的帮助下,我想出了这样的东西: #包括 #包括 #包括 #在...

回答 1 投票 0

MSVC 和 GCC/Clang 对于 constexpr 构造函数的区别

我希望得到一些帮助,以理解为什么以下代码不能在 MSVC (/std:c++20) 中编译,但可以在 GCC 和 Clang 中编译。 似乎可能与 constexpr 构造函数有关。 #包括...

回答 1 投票 0

MSVC 和 GCC/Clang 对于 consexpr 构造函数的区别

我希望得到一些帮助,以理解为什么以下代码不能在 MSVC (/std:c++20) 中编译,但可以在 GCC 和 Clang 中编译。 似乎可能与 constexpr 构造函数有关。 #包括...

回答 1 投票 0

如何通过 constexpr 函数剥离以 const char[] 形式给出的字符串?

我想定义一个 constexpr 函数 strip_string ,它允许: 修剪字符串(删除字符串开头和结尾的连续空格。 规范化...中的连续空格

回答 1 投票 0

如何在编译时获取 C++ 表达式的类型(即 constexpr'ly)?

我想在编译时使用类型的名称。例如,假设我写了: constexpr size_t my_strlen(const char* s) { const char* cp = s; while(*cp != ' ') { cp++...

回答 3 投票 0

在编译时计算编码 N 个不同状态所需的位数

我需要在编译时计算(结果将用作非类型模板参数)存储N个不同状态所需的最小位数: constexpr 无符号位需要(无符号 n)...

回答 7 投票 0

编译时字符串操作

我已经通读了我的问题的答案,但十年来还没有得到答案,所以我希望事情已经改变。 我正在寻找一种从 com 的 const char * 中删除空格的方法...

回答 1 投票 0

C++ 概念,如何检查 constexpr static int 是否等于 1,或类似...? Clang 不同意 GCC 和 MSVC

我无法在 cppreference 上找到与静态 constexpr 成员的值相匹配的概念的正确语法。该代码可以在 GCC 和 MSVC 上编译并正常运行,但无法在...

回答 1 投票 0

C++ 20 中的“constexpr”和 std::to_string

我有以下声明 - constexpr unsigned intcompileYear = (__DATE__[7] - '0') * 1000 + (__DATE__[8] - '0') * 100 + (__DATE__[9] - '0') * 10 + (__DATE__[10] - '0'); 使用 Visual Studi...

回答 1 投票 0

通过使用 constexpr 参数调用 constexpr 函数来初始化静态存储变量

我有以下无限递归 constexpr 函数: constexpr int foo(int x) { 返回 foo(x + 1); } 然后我发现 int main() { 静态 int x = foo(5); 静态 int y = std::

回答 1 投票 0

强制编译时 constexpr [重复]

在 C++11 中我们得到 constexpr: constexpr int foo (int x) { 返回x+1; } 是否可以使用动态值 x 来调用 foo 并引发编译时错误?也就是说,我想创建一个 foo...

回答 4 投票 0

回答 4 投票 0

constexpr 与 constexpr 内联与定义 - 优化 C 和 C++ 中的通用实用函数

我有一个简单的函数,在我的操作代码中为 C 编译,在测试中为 C++ 编译。由于我将在代码中广泛使用此函数,因此我想在实用程序文件中声明它并使其...

回答 1 投票 0

为什么 constexpr 函数中的参数不是常量表达式?

您能解释一下为什么这段代码无法编译吗? // 源.cpp constexpr const char* func(const char* s) { return s;} constexpr bool find(const char *param) { constexpr const char* 结果...

回答 1 投票 0

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.