You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by ya...@apache.org on 2026/04/15 15:20:26 UTC

(doris) branch master updated: [refine](function) enforce `final` on CRTP aggregate function derived classes to enable compiler devirtualization (#62433)

This is an automated email from the ASF dual-hosted git repository.

yanxuecheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 4e81acee0d8 [refine](function) enforce `final` on CRTP aggregate function derived classes to enable compiler devirtualization (#62433)
4e81acee0d8 is described below

commit 4e81acee0d83e1db3100a0eb8fe820d05c833c31
Author: Mryange <ya...@selectdb.com>
AuthorDate: Wed Apr 15 23:20:16 2026 +0800

    [refine](function) enforce `final` on CRTP aggregate function derived classes to enable compiler devirtualization (#62433)
    
    `IAggregateFunctionHelper<Derived>` implements hot aggregate paths such
    as `add_batch()` and `add_batch_single_place()` by calling
    `assert_cast<const Derived*>(this)->add(...)`. Because `add()` is
    declared `virtual` in `IAggregateFunction`, the compiler cannot
    devirtualize this call unless it can prove that `Derived` has no further
    overrides — which requires `Derived` to be marked `final`.
    
    This PR enforces this via a `static_assert` in the
    `IAggregateFunctionHelper` constructor. Note that `final` here is a
    **performance hint only** — correctness is not affected, since `add()`
    remains virtual and subclasses always dispatch correctly through the
    vtable regardless. Marking `Derived` as `final` allows the compiler to
    devirtualize (and potentially inline) the `add()` call inside hot
    aggregation paths.
    
    Changes:
    
    1. Add a `static_assert` in the `IAggregateFunctionHelper` constructor
    asserting `std::is_final_v<Derived>`, so that missing `final` is caught
    at compile time.
    2. Introduce `AggregateFunctionNonFinalBase` as an opt-out marker for
    classes that intentionally form inheritance hierarchies (e.g.
    `AggregateStateUnion → AggregateStateMerge`, `AggregateFunctionForEach →
    AggregateFunctionForEachV2`).
    3. Mark all concrete aggregate function classes `final` across
    `be/src/exprs/aggregate/`.
    4. Refactor `AggregateFunctionTopNBase` to accept a `Derived` template
    parameter so that `AggregateFunctionTopN` and
    `AggregateFunctionTopNArray` can each be marked `final`.
    5. Refactor `AggregateFunctionPercentileApprox` into
    `AggregateFunctionPercentileApproxBase<Derived>` so the four concrete
    specializations can each be marked `final`.
---
 be/src/exprs/aggregate/aggregate_function.h        | 32 ++++++++++-
 .../exprs/aggregate/aggregate_function_array_agg.h |  2 +-
 be/src/exprs/aggregate/aggregate_function_binary.h |  2 +-
 .../exprs/aggregate/aggregate_function_collect.h   |  2 +-
 be/src/exprs/aggregate/aggregate_function_covar.h  |  2 +-
 .../exprs/aggregate/aggregate_function_distinct.h  |  2 +-
 .../exprs/aggregate/aggregate_function_foreach.h   |  3 +-
 .../aggregate/aggregate_function_foreachv2.cpp     |  2 +-
 .../aggregate_function_group_array_set_op.h        |  2 +-
 .../aggregate/aggregate_function_hll_union_agg.h   |  2 +-
 .../aggregate/aggregate_function_percentile.h      | 63 ++++++++++++----------
 .../exprs/aggregate/aggregate_function_retention.h |  2 +-
 be/src/exprs/aggregate/aggregate_function_sort.h   |  2 +-
 .../aggregate/aggregate_function_state_union.h     |  3 +-
 .../exprs/aggregate/aggregate_function_statistic.h |  2 +-
 be/src/exprs/aggregate/aggregate_function_stddev.h |  2 +-
 be/src/exprs/aggregate/aggregate_function_topn.h   | 26 ++++-----
 .../aggregate/aggregate_function_window_funnel.h   |  2 +-
 .../aggregate_function_window_funnel_v2.h          |  2 +-
 19 files changed, 96 insertions(+), 59 deletions(-)

diff --git a/be/src/exprs/aggregate/aggregate_function.h b/be/src/exprs/aggregate/aggregate_function.h
index acc856056b0..da536f26ab1 100644
--- a/be/src/exprs/aggregate/aggregate_function.h
+++ b/be/src/exprs/aggregate/aggregate_function.h
@@ -303,12 +303,42 @@ protected:
     int version {};
 };
 
+/// Marker base for aggregate function classes that intentionally form an inheritance
+/// hierarchy (e.g. AggregateStateUnion -> AggregateStateMerge, or
+/// AggregateFunctionForEach -> AggregateFunctionForEachV2) and therefore cannot be
+/// marked 'final'. Classes that inherit this marker are exempt from the
+/// static_assert in IAggregateFunctionHelper.
+struct AggregateFunctionNonFinalBase {};
+
 /// Implement method to obtain an address of 'add' function.
 template <typename Derived>
 class IAggregateFunctionHelper : public IAggregateFunction {
 public:
     IAggregateFunctionHelper(const DataTypes& argument_types_)
-            : IAggregateFunction(argument_types_) {}
+            : IAggregateFunction(argument_types_) {
+        // NOTE: This static_assert is placed in the constructor body (not at class scope)
+        // because at class-scope instantiation time Derived is still an incomplete type,
+        // whereas the constructor body is instantiated lazily when a concrete object is
+        // constructed, at which point Derived is fully defined.
+        //
+        // Marking Derived as 'final' is an *optimization hint*, not a correctness
+        // requirement. add() is virtual in IAggregateFunction, so subclasses always
+        // dispatch correctly through the vtable regardless. However, when Derived is
+        // final, the compiler can see that assert_cast<const Derived*>(this)->add(...)
+        // inside add_batch() / add_batch_single_place() etc. has no further overrides,
+        // allowing it to devirtualize (and potentially inline) the add() call -- which
+        // is critical for hot aggregation paths.
+        //
+        // Classes that intentionally form inheritance hierarchies (and therefore accept
+        // the vtable overhead) must inherit AggregateFunctionNonFinalBase to opt out.
+        static_assert(
+                std::is_final_v<Derived> ||
+                        std::is_base_of_v<AggregateFunctionNonFinalBase, Derived>,
+                "Derived should be marked 'final' to allow the compiler to devirtualize "
+                "add() calls inside add_batch() and related hot paths. "
+                "If the class intentionally has subclasses, inherit AggregateFunctionNonFinalBase "
+                "to opt out of this check.");
+    }
 
     void destroy_vec(AggregateDataPtr __restrict place,
                      const size_t num_rows) const noexcept override {
diff --git a/be/src/exprs/aggregate/aggregate_function_array_agg.h b/be/src/exprs/aggregate/aggregate_function_array_agg.h
index e530cd34ae3..cf1dc2173a9 100644
--- a/be/src/exprs/aggregate/aggregate_function_array_agg.h
+++ b/be/src/exprs/aggregate/aggregate_function_array_agg.h
@@ -277,7 +277,7 @@ struct AggregateFunctionArrayAggData<T> {
 //ShowNull is just used to support array_agg because array_agg needs to display NULL
 //todo: Supports order by sorting for array_agg
 template <typename Data>
-class AggregateFunctionArrayAgg
+class AggregateFunctionArrayAgg final
         : public IAggregateFunctionDataHelper<Data, AggregateFunctionArrayAgg<Data>, true>,
           UnaryExpression,
           NotNullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_binary.h b/be/src/exprs/aggregate/aggregate_function_binary.h
index b3faca16e3f..d04bac39fd9 100644
--- a/be/src/exprs/aggregate/aggregate_function_binary.h
+++ b/be/src/exprs/aggregate/aggregate_function_binary.h
@@ -41,7 +41,7 @@ struct StatFunc {
 };
 
 template <typename StatFunc>
-struct AggregateFunctionBinary
+struct AggregateFunctionBinary final
         : public IAggregateFunctionDataHelper<typename StatFunc::Data,
                                               AggregateFunctionBinary<StatFunc>>,
           MultiExpression,
diff --git a/be/src/exprs/aggregate/aggregate_function_collect.h b/be/src/exprs/aggregate/aggregate_function_collect.h
index 55cd19045c4..831c4f04f90 100644
--- a/be/src/exprs/aggregate/aggregate_function_collect.h
+++ b/be/src/exprs/aggregate/aggregate_function_collect.h
@@ -392,7 +392,7 @@ struct AggregateFunctionCollectListData<T, HasLimit> {
 };
 
 template <typename Data, bool HasLimit>
-class AggregateFunctionCollect
+class AggregateFunctionCollect final
         : public IAggregateFunctionDataHelper<Data, AggregateFunctionCollect<Data, HasLimit>, true>,
           VarargsExpression,
           NotNullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_covar.h b/be/src/exprs/aggregate/aggregate_function_covar.h
index db3959c5f7a..e287dc060bd 100644
--- a/be/src/exprs/aggregate/aggregate_function_covar.h
+++ b/be/src/exprs/aggregate/aggregate_function_covar.h
@@ -137,7 +137,7 @@ struct SampData : BaseData<T> {
 };
 
 template <typename Data>
-class AggregateFunctionSampCovariance
+class AggregateFunctionSampCovariance final
         : public IAggregateFunctionDataHelper<Data, AggregateFunctionSampCovariance<Data>>,
           MultiExpression,
           NullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_distinct.h b/be/src/exprs/aggregate/aggregate_function_distinct.h
index 8a9dde16f6b..060817188b2 100644
--- a/be/src/exprs/aggregate/aggregate_function_distinct.h
+++ b/be/src/exprs/aggregate/aggregate_function_distinct.h
@@ -260,7 +260,7 @@ struct AggregateFunctionDistinctMultipleGenericData
   * Adding -Distinct suffix to aggregate function
 **/
 template <template <bool stable> typename Data, bool stable = false>
-class AggregateFunctionDistinct
+class AggregateFunctionDistinct final
         : public IAggregateFunctionDataHelper<Data<stable>,
                                               AggregateFunctionDistinct<Data, stable>>,
           VarargsExpression,
diff --git a/be/src/exprs/aggregate/aggregate_function_foreach.h b/be/src/exprs/aggregate/aggregate_function_foreach.h
index faa86d8303b..8afd5b93eaa 100644
--- a/be/src/exprs/aggregate/aggregate_function_foreach.h
+++ b/be/src/exprs/aggregate/aggregate_function_foreach.h
@@ -51,7 +51,8 @@ struct AggregateFunctionForEachData {
   *
   * TODO Allow variable number of arguments.
   */
-class AggregateFunctionForEach : public IAggregateFunctionDataHelper<AggregateFunctionForEachData,
+class AggregateFunctionForEach : public AggregateFunctionNonFinalBase,
+                                 public IAggregateFunctionDataHelper<AggregateFunctionForEachData,
                                                                      AggregateFunctionForEach>,
                                  VarargsExpression,
                                  NullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_foreachv2.cpp b/be/src/exprs/aggregate/aggregate_function_foreachv2.cpp
index 11a5a5cfba2..d8f0eac327a 100644
--- a/be/src/exprs/aggregate/aggregate_function_foreachv2.cpp
+++ b/be/src/exprs/aggregate/aggregate_function_foreachv2.cpp
@@ -35,7 +35,7 @@ namespace doris {
 // because we may have already assumed that the array's elements are always nullable types, and many places have such checks.
 // V1 code is kept to ensure compatibility during upgrades and downgrades.
 // V2 code differs from V1 only in the return type and insert_into logic; all other logic is exactly the same.
-class AggregateFunctionForEachV2 : public AggregateFunctionForEach {
+class AggregateFunctionForEachV2 final : public AggregateFunctionForEach {
 public:
     constexpr static auto AGG_FOREACH_SUFFIX = "_foreachv2";
     AggregateFunctionForEachV2(AggregateFunctionPtr nested_function_, const DataTypes& arguments)
diff --git a/be/src/exprs/aggregate/aggregate_function_group_array_set_op.h b/be/src/exprs/aggregate/aggregate_function_group_array_set_op.h
index f1b03402260..2eafcc337ab 100644
--- a/be/src/exprs/aggregate/aggregate_function_group_array_set_op.h
+++ b/be/src/exprs/aggregate/aggregate_function_group_array_set_op.h
@@ -405,7 +405,7 @@ struct GroupArrayStringUnionData : public GroupArraySetOpStringBaseData {
 
 /// Puts all values to the hybrid set. Returns an array of unique values
 template <typename ImplData>
-class AggregateFunctionGroupArraySetOp
+class AggregateFunctionGroupArraySetOp final
         : public IAggregateFunctionDataHelper<ImplData, AggregateFunctionGroupArraySetOp<ImplData>>,
           UnaryExpression,
           NotNullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_hll_union_agg.h b/be/src/exprs/aggregate/aggregate_function_hll_union_agg.h
index cd729422b90..5b45221e66a 100644
--- a/be/src/exprs/aggregate/aggregate_function_hll_union_agg.h
+++ b/be/src/exprs/aggregate/aggregate_function_hll_union_agg.h
@@ -100,7 +100,7 @@ struct AggregateFunctionHLLUnionAggImpl : Data {
 };
 
 template <typename Data>
-class AggregateFunctionHLLUnion
+class AggregateFunctionHLLUnion final
         : public IAggregateFunctionDataHelper<Data, AggregateFunctionHLLUnion<Data>>,
           UnaryExpression,
           NullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_percentile.h b/be/src/exprs/aggregate/aggregate_function_percentile.h
index 32423b4f87b..6a917460ffd 100644
--- a/be/src/exprs/aggregate/aggregate_function_percentile.h
+++ b/be/src/exprs/aggregate/aggregate_function_percentile.h
@@ -154,42 +154,40 @@ struct PercentileApproxState {
     float compressions = 10000;
 };
 
-class AggregateFunctionPercentileApprox
-        : public IAggregateFunctionDataHelper<PercentileApproxState,
-                                              AggregateFunctionPercentileApprox> {
+template <typename Derived>
+class AggregateFunctionPercentileApproxBase
+        : public IAggregateFunctionDataHelper<PercentileApproxState, Derived> {
 public:
-    AggregateFunctionPercentileApprox(const DataTypes& argument_types_)
-            : IAggregateFunctionDataHelper<PercentileApproxState,
-                                           AggregateFunctionPercentileApprox>(argument_types_) {}
+    AggregateFunctionPercentileApproxBase(const DataTypes& argument_types_)
+            : IAggregateFunctionDataHelper<PercentileApproxState, Derived>(argument_types_) {}
 
     String get_name() const override { return "percentile_approx"; }
 
-    void reset(AggregateDataPtr __restrict place) const override {
-        AggregateFunctionPercentileApprox::data(place).reset();
-    }
+    void reset(AggregateDataPtr __restrict place) const override { this->data(place).reset(); }
 
     void merge(AggregateDataPtr __restrict place, ConstAggregateDataPtr rhs,
                Arena&) const override {
-        AggregateFunctionPercentileApprox::data(place).merge(
-                AggregateFunctionPercentileApprox::data(rhs));
+        this->data(place).merge(this->data(rhs));
     }
 
     void serialize(ConstAggregateDataPtr __restrict place, BufferWritable& buf) const override {
-        AggregateFunctionPercentileApprox::data(place).write(buf);
+        this->data(place).write(buf);
     }
 
     void deserialize(AggregateDataPtr __restrict place, BufferReadable& buf,
                      Arena&) const override {
-        AggregateFunctionPercentileApprox::data(place).read(buf);
+        this->data(place).read(buf);
     }
 };
 
-class AggregateFunctionPercentileApproxTwoParams final : public AggregateFunctionPercentileApprox,
-                                                         public MultiExpression,
-                                                         public NullableAggregateFunction {
+class AggregateFunctionPercentileApproxTwoParams final
+        : public AggregateFunctionPercentileApproxBase<AggregateFunctionPercentileApproxTwoParams>,
+          public MultiExpression,
+          public NullableAggregateFunction {
 public:
     AggregateFunctionPercentileApproxTwoParams(const DataTypes& argument_types_)
-            : AggregateFunctionPercentileApprox(argument_types_) {}
+            : AggregateFunctionPercentileApproxBase<AggregateFunctionPercentileApproxTwoParams>(
+                      argument_types_) {}
     void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
              Arena&) const override {
         const auto& sources =
@@ -204,7 +202,7 @@ public:
 
     void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
         auto& col = assert_cast<ColumnFloat64&>(to);
-        double result = AggregateFunctionPercentileApprox::data(place).get();
+        double result = this->data(place).get();
 
         if (std::isnan(result)) {
             col.insert_default();
@@ -214,12 +212,15 @@ public:
     }
 };
 
-class AggregateFunctionPercentileApproxThreeParams final : public AggregateFunctionPercentileApprox,
-                                                           public MultiExpression,
-                                                           public NullableAggregateFunction {
+class AggregateFunctionPercentileApproxThreeParams final
+        : public AggregateFunctionPercentileApproxBase<
+                  AggregateFunctionPercentileApproxThreeParams>,
+          public MultiExpression,
+          public NullableAggregateFunction {
 public:
     AggregateFunctionPercentileApproxThreeParams(const DataTypes& argument_types_)
-            : AggregateFunctionPercentileApprox(argument_types_) {}
+            : AggregateFunctionPercentileApproxBase<AggregateFunctionPercentileApproxThreeParams>(
+                      argument_types_) {}
     void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
              Arena&) const override {
         const auto& sources =
@@ -238,7 +239,7 @@ public:
 
     void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
         auto& col = assert_cast<ColumnFloat64&>(to);
-        double result = AggregateFunctionPercentileApprox::data(place).get();
+        double result = this->data(place).get();
 
         if (std::isnan(result)) {
             col.insert_default();
@@ -249,12 +250,14 @@ public:
 };
 
 class AggregateFunctionPercentileApproxWeightedThreeParams final
-        : public AggregateFunctionPercentileApprox,
+        : public AggregateFunctionPercentileApproxBase<
+                  AggregateFunctionPercentileApproxWeightedThreeParams>,
           MultiExpression,
           NullableAggregateFunction {
 public:
     AggregateFunctionPercentileApproxWeightedThreeParams(const DataTypes& argument_types_)
-            : AggregateFunctionPercentileApprox(argument_types_) {}
+            : AggregateFunctionPercentileApproxBase<
+                      AggregateFunctionPercentileApproxWeightedThreeParams>(argument_types_) {}
 
     void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
              Arena&) const override {
@@ -274,7 +277,7 @@ public:
 
     void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
         auto& col = assert_cast<ColumnFloat64&>(to);
-        double result = AggregateFunctionPercentileApprox::data(place).get();
+        double result = this->data(place).get();
 
         if (std::isnan(result)) {
             col.insert_default();
@@ -285,12 +288,14 @@ public:
 };
 
 class AggregateFunctionPercentileApproxWeightedFourParams final
-        : public AggregateFunctionPercentileApprox,
+        : public AggregateFunctionPercentileApproxBase<
+                  AggregateFunctionPercentileApproxWeightedFourParams>,
           MultiExpression,
           NullableAggregateFunction {
 public:
     AggregateFunctionPercentileApproxWeightedFourParams(const DataTypes& argument_types_)
-            : AggregateFunctionPercentileApprox(argument_types_) {}
+            : AggregateFunctionPercentileApproxBase<
+                      AggregateFunctionPercentileApproxWeightedFourParams>(argument_types_) {}
     void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
              Arena&) const override {
         const auto& sources =
@@ -312,7 +317,7 @@ public:
 
     void insert_result_into(ConstAggregateDataPtr __restrict place, IColumn& to) const override {
         auto& col = assert_cast<ColumnFloat64&>(to);
-        double result = AggregateFunctionPercentileApprox::data(place).get();
+        double result = this->data(place).get();
 
         if (std::isnan(result)) {
             col.insert_default();
diff --git a/be/src/exprs/aggregate/aggregate_function_retention.h b/be/src/exprs/aggregate/aggregate_function_retention.h
index bcd5a5b5b96..ad6181d5ddb 100644
--- a/be/src/exprs/aggregate/aggregate_function_retention.h
+++ b/be/src/exprs/aggregate/aggregate_function_retention.h
@@ -105,7 +105,7 @@ struct RetentionState {
     }
 };
 
-class AggregateFunctionRetention
+class AggregateFunctionRetention final
         : public IAggregateFunctionDataHelper<RetentionState, AggregateFunctionRetention>,
           VarargsExpression,
           NullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_sort.h b/be/src/exprs/aggregate/aggregate_function_sort.h
index c0a42ef4b9e..e001cb0c4c4 100644
--- a/be/src/exprs/aggregate/aggregate_function_sort.h
+++ b/be/src/exprs/aggregate/aggregate_function_sort.h
@@ -114,7 +114,7 @@ struct AggregateFunctionSortData {
 };
 
 template <typename Data>
-class AggregateFunctionSort
+class AggregateFunctionSort final
         : public IAggregateFunctionDataHelper<Data, AggregateFunctionSort<Data>> {
 private:
     static constexpr auto prefix_size = sizeof(Data);
diff --git a/be/src/exprs/aggregate/aggregate_function_state_union.h b/be/src/exprs/aggregate/aggregate_function_state_union.h
index 9569db98398..1c8242bf53f 100644
--- a/be/src/exprs/aggregate/aggregate_function_state_union.h
+++ b/be/src/exprs/aggregate/aggregate_function_state_union.h
@@ -25,7 +25,8 @@
 namespace doris {
 const static std::string AGG_UNION_SUFFIX = "_union";
 
-class AggregateStateUnion : public IAggregateFunctionHelper<AggregateStateUnion> {
+class AggregateStateUnion : public AggregateFunctionNonFinalBase,
+                            public IAggregateFunctionHelper<AggregateStateUnion> {
 public:
     AggregateStateUnion(AggregateFunctionPtr function, const DataTypes& argument_types_,
                         DataTypePtr return_type)
diff --git a/be/src/exprs/aggregate/aggregate_function_statistic.h b/be/src/exprs/aggregate/aggregate_function_statistic.h
index e90978b1f99..56e92ebf65f 100644
--- a/be/src/exprs/aggregate/aggregate_function_statistic.h
+++ b/be/src/exprs/aggregate/aggregate_function_statistic.h
@@ -55,7 +55,7 @@ struct StatFuncOneArg {
 };
 
 template <typename StatFunc, bool NullableInput>
-class AggregateFunctionVarianceSimple
+class AggregateFunctionVarianceSimple final
         : public IAggregateFunctionDataHelper<
                   typename StatFunc::Data,
                   AggregateFunctionVarianceSimple<StatFunc, NullableInput>> {
diff --git a/be/src/exprs/aggregate/aggregate_function_stddev.h b/be/src/exprs/aggregate/aggregate_function_stddev.h
index 476744fde1d..a870b4695ff 100644
--- a/be/src/exprs/aggregate/aggregate_function_stddev.h
+++ b/be/src/exprs/aggregate/aggregate_function_stddev.h
@@ -175,7 +175,7 @@ struct StddevSampName {
 };
 
 template <typename Data>
-class AggregateFunctionSampVariance
+class AggregateFunctionSampVariance final
         : public IAggregateFunctionDataHelper<Data, AggregateFunctionSampVariance<Data>>,
           UnaryExpression,
           NullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_topn.h b/be/src/exprs/aggregate/aggregate_function_topn.h
index d887950cd09..0787a936e87 100644
--- a/be/src/exprs/aggregate/aggregate_function_topn.h
+++ b/be/src/exprs/aggregate/aggregate_function_topn.h
@@ -296,14 +296,12 @@ struct AggregateFunctionTopNImplWeight {
 };
 
 //base function
-template <typename Impl>
+template <typename Impl, typename Derived>
 class AggregateFunctionTopNBase
-        : public IAggregateFunctionDataHelper<typename Impl::Data,
-                                              AggregateFunctionTopNBase<Impl>> {
+        : public IAggregateFunctionDataHelper<typename Impl::Data, Derived> {
 public:
     AggregateFunctionTopNBase(const DataTypes& argument_types_)
-            : IAggregateFunctionDataHelper<typename Impl::Data, AggregateFunctionTopNBase<Impl>>(
-                      argument_types_) {}
+            : IAggregateFunctionDataHelper<typename Impl::Data, Derived>(argument_types_) {}
 
     void add(AggregateDataPtr __restrict place, const IColumn** columns, ssize_t row_num,
              Arena&) const override {
@@ -329,12 +327,13 @@ public:
 
 //topn function return string
 template <typename Impl>
-class AggregateFunctionTopN final : public AggregateFunctionTopNBase<Impl>,
-                                    MultiExpression,
-                                    NullableAggregateFunction {
+class AggregateFunctionTopN final
+        : public AggregateFunctionTopNBase<Impl, AggregateFunctionTopN<Impl>>,
+          MultiExpression,
+          NullableAggregateFunction {
 public:
     AggregateFunctionTopN(const DataTypes& argument_types_)
-            : AggregateFunctionTopNBase<Impl>(argument_types_) {}
+            : AggregateFunctionTopNBase<Impl, AggregateFunctionTopN<Impl>>(argument_types_) {}
 
     String get_name() const override { return "topn"; }
 
@@ -348,12 +347,13 @@ public:
 
 //topn function return array
 template <typename Impl>
-class AggregateFunctionTopNArray final : public AggregateFunctionTopNBase<Impl>,
-                                         MultiExpression,
-                                         NullableAggregateFunction {
+class AggregateFunctionTopNArray final
+        : public AggregateFunctionTopNBase<Impl, AggregateFunctionTopNArray<Impl>>,
+          MultiExpression,
+          NullableAggregateFunction {
 public:
     AggregateFunctionTopNArray(const DataTypes& argument_types_)
-            : AggregateFunctionTopNBase<Impl>(argument_types_),
+            : AggregateFunctionTopNBase<Impl, AggregateFunctionTopNArray<Impl>>(argument_types_),
               _argument_type(argument_types_[0]) {}
 
     String get_name() const override { return Impl::get_name(); }
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel.h b/be/src/exprs/aggregate/aggregate_function_window_funnel.h
index 69f81fdcb47..859a91c8451 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel.h
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel.h
@@ -341,7 +341,7 @@ struct WindowFunnelState {
     }
 };
 
-class AggregateFunctionWindowFunnel
+class AggregateFunctionWindowFunnel final
         : public IAggregateFunctionDataHelper<WindowFunnelState, AggregateFunctionWindowFunnel>,
           MultiExpression,
           NullableAggregateFunction {
diff --git a/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h b/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
index 759890f6f9e..fb0a72363b0 100644
--- a/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
+++ b/be/src/exprs/aggregate/aggregate_function_window_funnel_v2.h
@@ -616,7 +616,7 @@ private:
     }
 };
 
-class AggregateFunctionWindowFunnelV2
+class AggregateFunctionWindowFunnelV2 final
         : public IAggregateFunctionDataHelper<WindowFunnelStateV2, AggregateFunctionWindowFunnelV2>,
           MultiExpression,
           NullableAggregateFunction {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org