【问题标题】:Template function pointer parameter vs constructor argument模板函数指针参数与构造函数参数
【发布时间】:2019-10-12 19:57:50
【问题描述】:

对于如何传递一个函数指针,该函数指针将在整个对象生命周期中被类广泛使用,我感到两难。我想到了2个解决方案:

  • 将函数指针传递给构造函数并将其存储在类中:
    using Func = int(*)(int);

    class A
    {
    public:
        explicit A(int n, Func f) 
            : _f(f), _n(n)
        {}

        int Process()
        {
            return f(n);
        }

    private:
        Func _f;
        int _n;
    };
  • 或者使用模板参数:
    using Func = int(*)(int);

    template<Func f>
    class A
    {
    public:
        explicit A(int n) 
            : _n(n)
        {}

        int Process()
        {
            return f(n);
        }

    private:
        int _n;
    };

我认为模板解决方案更优雅,但我不确定它是否是最佳解决方案。 并且作为模板解决方案中的一个附属问题,如果只有Process方法使用模板参数,我是否仍然可以将构造函数放在源文件中,并将Process方法保留在头文件中?

【问题讨论】:

  • 模板方法的另一个好处是您对函数施加的任何约束都可以在编译时强制执行。

标签: c++ templates


【解决方案1】:

f 作为模板参数传递将导致为f 的每个不同值单独实例化模板。如果您担心这对代码大小的影响,请不要使用模板。如果不是,并且执行时间是最重要的,那么就去做吧。

std::sort 是使用模板参数可以加快执行速度的一个示例。如果您为比较函数传递一个常规的函数指针(如在 C 风格的qsort 中),那么调用它的时间通常占执行排序时间的很大一部分。 OTOH,std::sort 可以内联简单的比较函数,速度更快。

【讨论】:

  • 嗯,性能改进是我所指望的,对于单独的实例化我并不关心,因为函数指针可能是唯一的。我在这里使用不同的库来分离实现(在这个简单的例子中显然没有显示)。
【解决方案2】:

minor exceptionstemplates must be implemented in header files。如果您拥有 API 并且想要隐藏专有代码的实现方式,例如,因为任何人都可以简单地打开标题并查看它,这将是一个问题。

它还可能增加编译时间,因为模板类需要在编译时由编译器创建,而不是由链接器链接。

如果这些问题都没有困扰您,那么模板可能是一个不错的选择。一方面,正如你所说,它更有说服力,另一方面,它们非常灵活。如果您明天醒来并想使用不同类型的函数指针,那么您完全可以这样做。

当然,最终决定权在您手中,但希望您现在了解每种方法的优缺点。


编辑:不知怎的,我错过了你问题的最后一部分。

因此,代码的任何模板化部分都必须放在标头中。由于您的整个课程都是模板化的,因此您不能将其放在源文件中。

你可以做的是只做一个接受它作为参数的函数,它本身是模板化的:

    class A
    {
    public:
        explicit A(int n); // an go in C++ now

        template<Func f>
        int Process()
        {
            return f(n);
        }
        // ...
    };

但是,这样做将允许Process 接受任何独立于类的函数指针。也就是说,A 不再绑定到特定的f,而是对Process 的单独调用绑定到f。那可能不是你想要的。相反,执行选项 1 可能比我建议的选项 3 更好。但同样,这取决于您。

【讨论】:

  • 我已经看到你提到的第二个问题,我知道模板必须在头文件中实现才能与不同的参数一起使用。我的附属问题更多的是我是否可以在源文件中包含非模板位,而在标题中包含其余部分。编译器不会仍然获取带有模板参数的标头吗?
猜你喜欢
  • 2023-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-29
相关资源
最近更新 更多