这不是一个实际问题,但我正在寻找一种模式来改善以下逻辑:
void PrintToGameMasters()
{
std::string message = GetComplicatedDebugMessage(); // This will create a big string with various info
for (Player* player : GetAllPlayers())
if (player->IsGameMaster())
player->SendMessage(message);
}
Run Code Online (Sandbox Code Playgroud)
该代码有效,但我遇到的问题是,在大多数情况下,没有任何gamemasters参与者,因此消息编写将一事无成。
我想写一些只会在第一次使用该变量时就创建消息的东西,但是在这里我无法提出一个好的解决方案。
编辑:为了使这个问题更精确,我正在寻找一个不是特定于字符串的解决方案,它可能是一个没有函数来测试它是否已初始化的类型。如果我们可以将调用保持在GetComplicatedDebugMessage循环的顶部,这也是一个很大的奖励点,我认为一个涉及包装器的解决方案可以解决这个问题。
Jar*_*d42 77
尽管std::string具有空值,这可能意味着“未计算”,但是您可以更一般地使用std::optional处理空字符串和非默认可构造类型的值:
void PrintToGameMasters()
{
std::optional<std::string> message;
for (Player* player : GetAllPlayers()) {
if (player->IsGameMaster()) {
if (!message) {
message = GetComplicatedDebugMessage();
}
player->SendMessage(*message);
}
}
}
Run Code Online (Sandbox Code Playgroud)
rus*_*tyx 38
使用面向数据的设计;保留两个玩家列表:游戏大师和非游戏大师(或像您现在一样的所有玩家,以及指向游戏大师的指针的单独向量)。
void PrintToGameMasters()
{
auto players = GetGameMasters(); // Returns ONLY game master players
if (players.begin() != players.end()) {
std::string message = GetComplicatedDebugMessage();
for (Player* player : players) {
player->SendMessage(message);
}
}
}
Run Code Online (Sandbox Code Playgroud)
目标是最大程度地减少if循环内的陈述。
针对最常见的情况(而不是最普通的情况)进行优化;最常见的情况是玩家不是游戏高手;所以避免循环。
PS:由于您正在开发游戏,因此我想将此链接添加到Mike Acton的cppcon演讲中,您可能会觉得很有趣。
Lig*_*ica 36
这里有一些好主意,但我想使其更简单一些:
void PrintToGameMasters()
{
std::string message;
for (Player* player : GetAllPlayers())
{
if (player->IsGameMaster())
{
if (message.empty())
message = GetComplicatedDebugMessage();
player->SendMessage(message);
}
}
}
Run Code Online (Sandbox Code Playgroud)
每个人都可以遵循它,并且它像芯片一样便宜……再加上调试起来也很容易。
Nat*_*ica 30
您可以std::call_once在第一次找到游戏大师时使用lambda来调用该函数
void PrintToGameMasters()
{
std::once_flag of;
std::string message;
for (Player* player : GetAllPlayers())
if (player->IsGameMaster())
{
std::call_once(of, [&](){ message = GetComplicatedDebugMessage(); });
player->SendMessage(message);
}
}
Run Code Online (Sandbox Code Playgroud)
Nik*_* C. 13
将消息包装在可变的lambda中:
auto makeMessage = [message = std::string()]() mutable -> std::string&
{
if (message.empty()) {
message = GetComplicatedDebugMessage();
}
return message;
};
for (Player* player : GetAllPlayers())
if (player->IsGameMaster())
player->SendMessage(makeMessage());
Run Code Online (Sandbox Code Playgroud)
小智 5
std::optional您可以扩展使用(如 Jarod41 的答案)的方法,并在顶部进行惰性评估。这也将满足“将调用保持GetComplicatedDebugMessage在循环顶部”的要求。
template <typename T>
class Lazy : public std::optional<T> {
public:
Lazy(std::function<T()> f) : fn(f) { }
T operator*() {
if (!*this)
std::optional<T>::operator=(fn());
return this->value();
}
private:
std::function<T()> fn;
};
void PrintToGameMasters()
{
Lazy<std::string> message(GetComplicatedDebugMessage);
for (Player* player : GetAllPlayers())
if (player->IsGameMaster())
player->SendMessage(*message);
}
Run Code Online (Sandbox Code Playgroud)
不确定这是否是最佳模式,但您可以使用 lambda 延迟计算:
void PrintToGameMasters()
{
std::string message = "";
auto getDebugMessage = [&message]() -> const std::string& {
if (message.empty()) {
message = GetComplicatedDebugMessage();
}
return message;
};
for (Player* player : GetAllPlayers())
if (player->IsGameMaster())
player->SendMessage(getDebugMessage());
}
Run Code Online (Sandbox Code Playgroud)