部分成员函数模板专门化和数据成员访问

2023-12-05

我有一个关于模板化成员函数的部分专业化的问题。

背景:目标是计算大型数据集的描述性统计数据,这些数据集太大而无法一次保存在内存中。因此,我有方差和协方差的累加器类,我可以在其中逐个推入数据集(一次一个值或更大的块)。仅计算算术平均值的相当简化的版本是

class Mean
{
private:
    std::size_t _size;
    double _mean;
public:
    Mean() : _size(0), _mean(0)
    {
    }
    double mean() const
    {
        return _mean;
    }
    template <class T> void push(const T value)
    {
        _mean += (value - _mean) / ++_size;
    }
    template <class InputIt> void push(InputIt first, InputIt last)
    {
        for (; first != last; ++first)
        {
            _mean += (*first - _mean) / ++_size;
        }
    }
};

这种累加器类的一个特殊优点是可以将不同数据类型的值推入同一累加器类。

Problem:这适用于所有整数数据类型。然而,累加器类应该能够通过首先计算绝对值 |z| 来处理复数。然后将其推入累加器。为了推送单个值,很容易提供重载方法

template <class T> void push(const std::complex<T> z)
{
    T a = std::real(z);
    T b = std::imag(z);
    push(std::sqrt(a * a + b * b));
}

然而,对于通过迭代器推送数据块,情况并不那么简单。为了正确重载,需要部分特化,因为我们需要知道实际的(完全特化的)复数类型。通常的方法是将实际代码委托在内部结构中并相应地对其进行专门化

// default version for all integral types
template <class InputIt, class T>
struct push_impl
{
    static void push(InputIt first, InputIt last)
    {
        for (; first != last; ++first)
        {
            _mean += (*first - _mean) / ++_size;
        }
    }
};

// specialised version for complex numbers of any type
template <class InputIt, class T>
struct push_impl<InputIt, std::complex<T>>
{
    static void push(InputIt first, InputIt last)
    {
        for (; first != last; ++first)
        {
            T a = std::real(*first);
            T b = std::imag(*first);
            _mean += (std::sqrt(a * a + b * b) - _mean) / ++_size;
        }
    }
};

在累加器类中,然后调用委托结构的模板化方法

template <class InputIt>
void push(InputIt first, InputIt last)
{
    push_impl<InputIt, typename std::iterator_traits<InputIt>::value_type>::push(first, last);
}

然而,这种技术有一个问题,即如何访问累加器类的私有成员。由于它们是不同的类,所以不可能直接访问,而且 push_impl 的方法必须是静态的,并且不能访问累加器的非静态成员。

我可以想到以下四种解决该问题的方法,它们各有优缺点:

  1. 创建一个实例推送实现在每次通话中push由于额外的副本而(可能)导致性能下降。
  2. 有一个实例推送实现作为累加器类的成员变量,这将阻止我将不同的数据类型推入累加器,因为实例必须完全专业化。
  3. 将累加器类的所有成员公开并通过*this to 推送实现::push()来电。由于封装的破坏,这是一个特别糟糕的解决方案。
  4. 根据单值版本实现迭代器版本,即调用push()由于额外的函数调用,每个元素的方法(可能)会降低性能。

请注意,上述性能下降本质上是理论上的,由于编译器巧妙的内联,可能根本没有问题,但实际情况push方法可能比上面的示例复杂得多。

一种解决方案比其他解决方案更好还是我错过了什么?

致以最诚挚的问候和非常的感谢。


正如所评论的,您根本不需要为此使用部分专业化,实际上部分专业化通常很容易避免,并且最好避免。

private:
template <class T>
struct tag{}; // trivial nested struct

template <class I, class T> 
void push_impl(I first, I last, tag<T>) { ... } // generic implementation

template <class I, class T>
void push_impl(I first, I last, tag<std::complex<T>>) { ... } // complex implementation

public:
template <class InputIt>
void push(InputIt first, InputIt last)
{
    push_impl(first, last,
              tag<typename std::iterator_traits<InputIt>::value_type> {});
}

Since push_impl是一个(私有)成员函数,您不需要再做任何特殊的事情。

与您提出的解决方案相比,这没有额外的性能成本。函数调用次数相同,唯一的区别是按值传递无状态类型,这对于编译器来说是完全微不足道的优化。而且封装方面也没有任何牺牲。并且样板代码稍微少一些。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

部分成员函数模板专门化和数据成员访问 的相关文章

随机推荐

  • 是否有基于任务的 System.Threading.Timer 替代品?

    我是 Net 4 0 任务的新手 我无法找到我认为是基于任务的计时器替换或实现 例如周期性任务 有这样的事吗 Update 它取决于 4 5 但这有效 public class PeriodicTask public static asyn
  • CakePHP - 删除级联不起作用

    在 CakePHP 中 我有一个模型 Type 和 SpecificType SpecificType 属于一个 Type type id 字段 当我删除SpecificType的条目时 如何才能同时删除Type 我把它作为 this gt
  • .filter() 函数返回未定义而不是过滤数组

    我正在尝试理解 javascriptArray filter方法 为什么下面的代码会返回undefined 我缺少什么 function driversWithRevenueOver driver revenue driver filter
  • 使用OpenGL绘制圆的一部分?

    我只想画一个部门 部分3d 圆的 给出 2 个角度 起点 终点 圆心坐标 半径和宽度 你能帮我做那件事吗 计算圆上点的公式 给定半径 圆心 x0 y0 和角度 以弧度为单位 float x radius cos angle x0 float
  • C++ 高效使用 new 运算符

    当用 new 实例化一个类时 如果不删除内存 我们会通过对象的重用获得哪些好处 新的流程是怎样的 是否发生上下文切换 新的内存被分配了 谁来分配 操作系统 你在这里问了几个问题 Instead of deleting the memory
  • 是否存在与 PE 基址重定位等效的 ELF?

    我一直在研究一些 ELF 二进制文件的反汇编 我注意到了这一点 0000000000401020 lt start gt 401020 31 ed xor ebp ebp 401022 49 89 d1 mov r9 rdx 401025
  • pysftp -- paramiko SSHException,来自服务器的错误主机密钥

    我正在尝试通过以下方式连接到远程主机pysftp try with pysftp Connection inventory 0 username transit private key ssh id rsa sftp port 8055 a
  • 根据数组中的元素作为索引删除数组元素

    假设我有一个数组 let arr1 0 2 This is always sorted 注意 数组中的这些元素表示要从另一个数组中删除的索引 我有另一个数组 let arrOvj 1 4 6 7 21 17 12 我想删除 arrObj 的
  • 如何使用同一台 Mac 在不同版本的 OSx 上测试和调试 Cocoa App?

    我使用 Mac 和 Yosemite 制作了一个应用程序 完成后 我将其存档 然后分发给几个朋友 其中一个拥有小牛队 我在 Mavericks 系统上遇到了一些问题 随着这件事情的发生 我心中产生了以下疑问 我可以在不同的 OSX 版本上检
  • 让 UITableViewCell 使用自动布局调整自身大小

    我有 3 个标签UITableViewCell并设置标签 以便它们自动换行 如果自动换行 文本将进入下一个单元格 如何让 AutoLayout 根据内容展开单元格 而无需在中编写代码heightForRowAtIndex方法 是否没有一个约
  • 使用 String.Format 自定义格式时间跨度

    我想将时间跨度格式化为这样的格式 49 hr 34 mn 20 sec 我使用了下面的字符串格式 String Format 0 00 1 00 2 00 theTimeSpan TotalHours theTimeSpan Minutes
  • erlang 中的数组实现

    我的问题是 与列表相反 在 Erlang 中如何实现数组 使用不可变类型做类似的事情 move X Xs Ys gt X Ys Ls move 1 2 3 2 3 4 将占用堆中的常量内存 因为这都是参考工作 但是对于数组中的相同内容 mo
  • 在 Three.js 点云中显示深度

    I have a 3D scan of a rock that I have represented as a point cloud using Three js and I wanted to more explicitly show
  • 优化 JSON 序列化器/反序列化器作为扩展方法?

    我想尽可能轻松地将任何对象序列化为 JSON 然后简单地将其转换回 type safe 对象 谁能告诉我 FromJSONString 扩展方法中我做错了什么 Edit 为了您的方便 下面是一个完整且功能齐全的扩展方法 如果您发现错误 请告
  • HttpServletRequest.getSession(false):什么时候返回null?

    我想知道什么时候调用时会出现 null HttpServletRequest getSession 假 另外 有关于 HttpSession 的好的教程吗 我想获得以下详细信息 何时 invalidate 后果是什么 我需要检查返回的 Ht
  • 为什么Python中的for循环之前不能使用分号?

    我可以在 Python 中使用分号连接行 例如 a 5 b 10 但为什么我不能对 for 做同样的事情 x a b for i j in enumerate x print i j 因为Python语法不允许这样做 看文档 stmt li
  • 分析Java中的全角或半角字符

    我想分析 char 数组中的全角或半角字符 例如 char 密码 t e s t 思 题 这个char数组中有全角和半角字符 半宽 t e s t 全角 思 题 那么 如何在java中分析char数组的全角或半角呢 多谢 东亚字符的宽度描述
  • jsp - 从 java 字符串设置输入标记 (html) 的值

    我在这里面临一个奇怪的问题 情况是这样的 我正在尝试设置一个值input来自java字符串的标签
  • 递归方法:我们如何生成括号上的所有可能性?

    我们怎样才能在大括号上生成所有可能性 N值已经给了我们 我们要产生所有的可能性 例子 1 如果 N 1 则只有一种可能性 2 如果 N 2 则可能性为 3 如果 N 3 则可能性为 注意 左括号和右括号应该匹配 我的意思是 对于 N 1 无
  • 部分成员函数模板专门化和数据成员访问

    我有一个关于模板化成员函数的部分专业化的问题 背景 目标是计算大型数据集的描述性统计数据 这些数据集太大而无法一次保存在内存中 因此 我有方差和协方差的累加器类 我可以在其中逐个推入数据集 一次一个值或更大的块 仅计算算术平均值的相当简化的