我正在使用 constexpr 函数(字符串 -> NFA -> DFA)用 C++ 编写一个简单的编译时正则表达式解析器。但是,我无法将我的一些类方法设置为 constexpr。我尝试了各种组合,但似乎我必须实现我自己的
std::shared_ptr
版本,它是每个成员函数的 constexpr 。
有人可以帮我吗?这似乎是一个微不足道的问题,因为
new
和 delete
现在有 constexpr 支持,但我仍然无法声明我的方法 constexpr。这是代码:
#include <memory>
#include <variant>
#include <iostream>
#include <utility>
#include <cstdint>
#include <vector>
#include <bit>
#include <source_location>
#include <array>
#include <string_view>
#include <algorithm>
#include <type_traits>
#include <limits>
struct Node
{
private:
friend class NodeManager;
std::size_t unique_index{ std::numeric_limits<std::size_t>::max() };
public:
std::vector<std::shared_ptr<Node>> empty_transitions{};
std::vector<std::pair<std::string, std::shared_ptr<Node>>> tran_nodes{};
};
class NodeManager
{
public:
constexpr NodeManager() = default;
constexpr NodeManager(const NodeManager&) = delete;
constexpr NodeManager(NodeManager&&) = delete;
constexpr NodeManager& operator=(const NodeManager&) = delete;
constexpr NodeManager& operator=(NodeManager&&) = delete;
std::vector<std::shared_ptr<Node>> all_nodes;
constexpr auto create_node() -> std::shared_ptr<Node>
{
all_nodes.emplace_back(std::make_shared<Node>());
all_nodes.back()->unique_index = all_nodes.size() - 1;
return all_nodes.back();
}
constexpr auto get_node_count() const
{
return all_nodes.size();
}
constexpr void delete_node(std::shared_ptr<Node> node)
{
auto index = std::exchange(node->unique_index, std::numeric_limits<std::size_t>::max());
all_nodes[index] = nullptr;
if (index != all_nodes.size() - 1)
{
std::swap(all_nodes[index], all_nodes.back());
all_nodes[index]->unique_index = index;
}
all_nodes.pop_back();
}
constexpr void garbage_collect()
{
for (int i = 0; i < all_nodes.size(); ++i)
{
if (all_nodes[i].use_count() > 1)
continue;
delete_node(all_nodes[i]);
}
}
constexpr void delete_all_nodes()
{
all_nodes.clear();
}
};
constexpr auto foo()
{
auto ptr = NodeManager().create_node();
return 5;
}
int main()
{
constexpr auto x = foo();
return 0;
}
这是我收到的编译错误:
example.cpp
<source>(36): error C3615: constexpr function 'NodeManager::create_node' cannot result in a constant expression
<source>(36): note: failure was because type 'std::shared_ptr<Node>' is not a literal type
C:/data/msvc/14.39.33321-Pre/include\memory(1649): note: type 'std::shared_ptr<Node>' is not a literal type because it has a user-defined destructor
<source>(39): note: failure was caused by call of undefined function or one not declared 'constexpr'
<source>(39): note: see usage of 'std::shared_ptr<Node>::operator ->'
<source>(40): note: failure was caused by call of undefined function or one not declared 'constexpr'
<source>(40): note: see usage of 'std::shared_ptr<Node>::shared_ptr'
<source>(48): error C3615: constexpr function 'NodeManager::delete_node' cannot result in a constant expression
<source>(48): note: failure was because type 'std::shared_ptr<Node>' is not a literal type
C:/data/msvc/14.39.33321-Pre/include\memory(1649): note: type 'std::shared_ptr<Node>' is not a literal type because it has a user-defined destructor
<source>(51): note: failure was caused by call of undefined function or one not declared 'constexpr'
<source>(51): note: see usage of 'std::shared_ptr<Node>::operator ='
<source>(87): error C2131: expression did not evaluate to a constant
<source>(81): note: function violates 'constexpr' rules or has errors
<source>(81): note: see usage of 'NodeManager::create_node'
<source>(87): note: the call stack of the evaluation (the oldest call first) is
<source>(87): note: while evaluating function 'int foo(void)'
<source>(81): note: while evaluating function 'std::shared_ptr<Node> NodeManager::create_node(void)'
Compiler returned: 2
Godbolt 链接:https://godbolt.org/z/YbsrferP6
谢谢!
编译器错误告诉你出了什么问题:
<source>(40): note: failure was caused by call of undefined function or one not declared 'constexpr'
<source>(40): note: see usage of 'std::shared_ptr<Node>::shared_ptr
shared_ptr 不是 constexpr(有关 make_shared 和 shared_ptr,请参阅 cppreference)。 unique_ptr 可以用于 constexpr,但仅从 c++23 开始。我不确定operator new是否可以在c++20中使用constexpr,我认为这也需要c++23?
无论哪种方式,即使你可以切换到c++23,你也需要使用unique_ptr而不是shared_ptr。