remove_pointer 对于 unique_ptr 的
remove_pointer for unique_ptr's
假设我正在编写一个带有可玩 AI 的棋盘游戏。 class Board
有两个模板参数:P 和 N。N 是玩家的数量。 P 是 unique_ptr<Player>
或 Player
。我在实际玩游戏时使用unique_ptr<Player>
,因为Player
有两个child class(Human
和AI
),但是当AI搜索游戏状态,它使用相同的 Board
class 但 T = Player(我选择这个是为了潜在的性能提升,例如数据将是本地的,间接性更少,堆应该更少碎片化)。
问题: 我如何定义运算符[],其中 returns 是对其中一名玩家的引用(例如,如果 T = unique_ptr 它 returns *arr_[i],否则 returns arr_[i])。下面是一个尝试,但没有编译。另外,请随意评论设计(例如,理论上,我真的可以通过引入 P 看到性能提升吗?)。
template<typename P, size_t N>
class Board
{
public:
P& operator[] (size_t idx) { return helper(arr[idx]); }
private:
template<typename I, typename O>
inline O& helper(I& input)
{
return input;
}
template<>
inline P& helper<unique_ptr<P>,P>(unique_ptr<P> input)
{
return *input;
}
std::array<P,N> arr_;
};
编译器错误:
- non-namespace 范围 'class Foo'
的显式专业化
- template-id helper,T> 在声明中
主模板
Also, feel free to comment on design (e.g. in theory, can I really see a performance gain by introducing P?).
好的:
您甚至在代码编译之前就试图以可维护性换取性能。这是最邪恶的早期优化。
unique_ptr 管理所有权。将它用作您正在寻求做的逻辑开关是交易可维护性和可读性(大时间)以获得尚未确认的性能提升(参见 1)。将 unique_ptr 传递给函数的唯一原因是函数 绝对必须知道 数据由 unique_ptr 管理。这是很少见的(阅读:永远不要这样做)除非你正在转让所有权或者你正在编写一个旨在访问 unique_ptrs
集合的访问者
关于代码最重要的事情是这些(按重要性排序):
- 它编译
- 有效
- 逻辑正确,无bug,不泄露资源
- 易于维护
- 真的很容易维护
- 您的用户喜欢使用它
- 在这一点上,您可以尝试实现关于编写您能编写的最高效代码的自恋幻想(通常没有充分的理由)。你会失败,但你确实有更好的事情要做——比如让游戏变得更好,玩起来更有趣。
担心性能的时候是当您的用户被完美运行的软件所宠坏时,使用起来非常愉快,他们唯一能想到的担心就是游戏只给他们 299.99每秒帧数,他们认为它确实应该提供 300。
我不会评论这背后的逻辑,但实现它只需要引入一个辅助函数:并使用辅助函数的 return 类型。您在尝试中看到的问题是您的 operator[] 只是 returned P&
- 如果 P
是 std::unique_ptr<T,D>
.
要使用 helper 的 return 类型,我们只需将其设为 private static 并依赖 decltype
:
template <typename P, size_t N>
class Board {
private:
template <typename T, typename D>
static T& get_helper(std::unique_ptr<T,D>& val) { return *val; }
template <typename T>
static T& get_helper(T& val) { return val; }
public:
decltype(get_helper(std::declval<P&>())) // use the same return type
// as the helper function
operator[] (size_t idx) {
return get_helper(arr_[idx]);
}
private:
std::array<P,N> arr_;
};
在C++14中,注释掉的行可以是decltype(auto)
.
假设我正在编写一个带有可玩 AI 的棋盘游戏。 class Board
有两个模板参数:P 和 N。N 是玩家的数量。 P 是 unique_ptr<Player>
或 Player
。我在实际玩游戏时使用unique_ptr<Player>
,因为Player
有两个child class(Human
和AI
),但是当AI搜索游戏状态,它使用相同的 Board
class 但 T = Player(我选择这个是为了潜在的性能提升,例如数据将是本地的,间接性更少,堆应该更少碎片化)。
问题: 我如何定义运算符[],其中 returns 是对其中一名玩家的引用(例如,如果 T = unique_ptr 它 returns *arr_[i],否则 returns arr_[i])。下面是一个尝试,但没有编译。另外,请随意评论设计(例如,理论上,我真的可以通过引入 P 看到性能提升吗?)。
template<typename P, size_t N>
class Board
{
public:
P& operator[] (size_t idx) { return helper(arr[idx]); }
private:
template<typename I, typename O>
inline O& helper(I& input)
{
return input;
}
template<>
inline P& helper<unique_ptr<P>,P>(unique_ptr<P> input)
{
return *input;
}
std::array<P,N> arr_;
};
编译器错误:
- non-namespace 范围 'class Foo' 的显式专业化
- template-id helper,T> 在声明中 主模板
Also, feel free to comment on design (e.g. in theory, can I really see a performance gain by introducing P?).
好的:
您甚至在代码编译之前就试图以可维护性换取性能。这是最邪恶的早期优化。
unique_ptr 管理所有权。将它用作您正在寻求做的逻辑开关是交易可维护性和可读性(大时间)以获得尚未确认的性能提升(参见 1)。将 unique_ptr 传递给函数的唯一原因是函数 绝对必须知道 数据由 unique_ptr 管理。这是很少见的(阅读:永远不要这样做)除非你正在转让所有权或者你正在编写一个旨在访问 unique_ptrs
集合的访问者
关于代码最重要的事情是这些(按重要性排序):
- 它编译
- 有效
- 逻辑正确,无bug,不泄露资源
- 易于维护
- 真的很容易维护
- 您的用户喜欢使用它
- 在这一点上,您可以尝试实现关于编写您能编写的最高效代码的自恋幻想(通常没有充分的理由)。你会失败,但你确实有更好的事情要做——比如让游戏变得更好,玩起来更有趣。
担心性能的时候是当您的用户被完美运行的软件所宠坏时,使用起来非常愉快,他们唯一能想到的担心就是游戏只给他们 299.99每秒帧数,他们认为它确实应该提供 300。
我不会评论这背后的逻辑,但实现它只需要引入一个辅助函数:并使用辅助函数的 return 类型。您在尝试中看到的问题是您的 operator[] 只是 returned P&
- 如果 P
是 std::unique_ptr<T,D>
.
要使用 helper 的 return 类型,我们只需将其设为 private static 并依赖 decltype
:
template <typename P, size_t N>
class Board {
private:
template <typename T, typename D>
static T& get_helper(std::unique_ptr<T,D>& val) { return *val; }
template <typename T>
static T& get_helper(T& val) { return val; }
public:
decltype(get_helper(std::declval<P&>())) // use the same return type
// as the helper function
operator[] (size_t idx) {
return get_helper(arr_[idx]);
}
private:
std::array<P,N> arr_;
};
在C++14中,注释掉的行可以是decltype(auto)
.