Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-17 09:29:18

0001 /// \file
0002 /// \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
0003 /// Feedback is welcome!
0004 
0005 #ifndef ROOT_RHist
0006 #define ROOT_RHist
0007 
0008 #include "RAxisVariant.hxx"
0009 #include "RBinIndex.hxx"
0010 #include "RBinIndexMultiDimRange.hxx"
0011 #include "RCategoricalAxis.hxx"
0012 #include "RHistEngine.hxx"
0013 #include "RHistStats.hxx"
0014 #include "RRegularAxis.hxx"
0015 #include "RWeight.hxx"
0016 
0017 #include <array>
0018 #include <cstddef>
0019 #include <cstdint>
0020 #include <stdexcept>
0021 #include <tuple>
0022 #include <utility>
0023 #include <variant>
0024 #include <vector>
0025 
0026 class TBuffer;
0027 
0028 namespace ROOT {
0029 namespace Experimental {
0030 
0031 // forward declaration for friend declaration
0032 template <typename BinContentType>
0033 class RHistFillContext;
0034 
0035 /**
0036 A histogram for aggregation of data along multiple dimensions.
0037 
0038 Every call to \ref Fill(const A &... args) "Fill" increments the bin content and is reflected in global statistics:
0039 \code
0040 ROOT::Experimental::RHist<int> hist(10, {5, 15});
0041 hist.Fill(8.5);
0042 // hist.GetBinContent(ROOT::Experimental::RBinIndex(3)) will return 1
0043 \endcode
0044 
0045 The class is templated on the bin content type. For counting, as in the example above, it may be an integral type such
0046 as `int` or `long`. Narrower types such as `unsigned char` or `short` are supported, but may overflow due to their
0047 limited range and must be used with care. For weighted filling, the bin content type must not be an integral type, but
0048 a floating-point type such as `float` or `double`, or the special type RBinWithError. Note that `float` has a limited
0049 significand precision of 24 bits.
0050 
0051 An object can have arbitrary dimensionality determined at run-time. The axis configuration is passed as a vector of
0052 RAxisVariant:
0053 \code
0054 std::vector<ROOT::Experimental::RAxisVariant> axes;
0055 axes.push_back(ROOT::Experimental::RRegularAxis(10, {5, 15}));
0056 axes.push_back(ROOT::Experimental::RVariableBinAxis({1, 10, 100, 1000}));
0057 ROOT::Experimental::RHist<int> hist(axes);
0058 // hist.GetNDimensions() will return 2
0059 \endcode
0060 
0061 \warning This is part of the %ROOT 7 prototype! It will change without notice. It might trigger earthquakes.
0062 Feedback is welcome!
0063 */
0064 template <typename BinContentType>
0065 class RHist final {
0066    // For conversion, all other template instantiations must be a friend.
0067    template <typename U>
0068    friend class RHist;
0069 
0070    friend class RHistFillContext<BinContentType>;
0071 
0072    /// The histogram engine including the bin contents.
0073    RHistEngine<BinContentType> fEngine;
0074    /// The global histogram statistics.
0075    RHistStats fStats;
0076 
0077    /// Private constructor based off an engine.
0078    RHist(RHistEngine<BinContentType> engine) : fEngine(std::move(engine)), fStats(fEngine.GetNDimensions()) {}
0079 
0080 public:
0081    /// Construct a histogram.
0082    ///
0083    /// \param[in] axes the axis objects, must have size > 0
0084    explicit RHist(std::vector<RAxisVariant> axes) : fEngine(std::move(axes)), fStats(fEngine.GetNDimensions())
0085    {
0086       // The axes parameter was moved, use from the engine.
0087       const auto &engineAxes = fEngine.GetAxes();
0088       for (std::size_t i = 0; i < engineAxes.size(); i++) {
0089          if (engineAxes[i].GetCategoricalAxis() != nullptr) {
0090             fStats.DisableDimension(i);
0091          }
0092       }
0093    }
0094 
0095    /// Construct a histogram.
0096    ///
0097    /// Note that there is no perfect forwarding of the axis objects. If that is needed, use the
0098    /// \ref RHist(std::vector<RAxisVariant> axes) "overload accepting a std::vector".
0099    ///
0100    /// \param[in] axes the axis objects, must have size > 0
0101    explicit RHist(std::initializer_list<RAxisVariant> axes) : RHist(std::vector(axes)) {}
0102 
0103    /// Construct a histogram.
0104    ///
0105    /// Note that there is no perfect forwarding of the axis objects. If that is needed, use the
0106    /// \ref RHist(std::vector<RAxisVariant> axes) "overload accepting a std::vector".
0107    ///
0108    /// \param[in] axis1 the first axis object
0109    /// \param[in] axes the remaining axis objects
0110    template <typename... Axes>
0111    explicit RHist(const RAxisVariant &axis1, const Axes &...axes) : RHist(std::vector<RAxisVariant>{axis1, axes...})
0112    {
0113    }
0114 
0115    /// Construct a one-dimensional histogram with a regular axis.
0116    ///
0117    /// \param[in] nNormalBins the number of normal bins, must be > 0
0118    /// \param[in] interval the axis interval (lower end inclusive, upper end exclusive)
0119    /// \par See also
0120    /// the \ref RRegularAxis::RRegularAxis(std::uint64_t nNormalBins, std::pair<double, double> interval, bool
0121    /// enableFlowBins) "constructor of RRegularAxis"
0122    RHist(std::uint64_t nNormalBins, std::pair<double, double> interval)
0123       : RHist(std::vector<RAxisVariant>{RRegularAxis(nNormalBins, interval)})
0124    {
0125    }
0126 
0127    /// The copy constructor is deleted.
0128    ///
0129    /// Copying all bin contents can be an expensive operation, depending on the number of bins. If required, users can
0130    /// explicitly call Clone().
0131    RHist(const RHist &) = delete;
0132    /// Efficiently move construct a histogram.
0133    ///
0134    /// After this operation, the moved-from object is invalid.
0135    RHist(RHist &&) = default;
0136 
0137    /// The copy assignment operator is deleted.
0138    ///
0139    /// Copying all bin contents can be an expensive operation, depending on the number of bins. If required, users can
0140    /// explicitly call Clone().
0141    RHist &operator=(const RHist &) = delete;
0142    /// Efficiently move a histogram.
0143    ///
0144    /// After this operation, the moved-from object is invalid.
0145    RHist &operator=(RHist &&) = default;
0146 
0147    ~RHist() = default;
0148 
0149    /// \name Accessors
0150    /// \{
0151 
0152    const RHistEngine<BinContentType> &GetEngine() const { return fEngine; }
0153    const RHistStats &GetStats() const { return fStats; }
0154 
0155    const std::vector<RAxisVariant> &GetAxes() const { return fEngine.GetAxes(); }
0156    std::size_t GetNDimensions() const { return fEngine.GetNDimensions(); }
0157    std::uint64_t GetTotalNBins() const { return fEngine.GetTotalNBins(); }
0158 
0159    std::uint64_t GetNEntries() const { return fStats.GetNEntries(); }
0160 
0161    /// \}
0162    /// \name Computations
0163    /// \{
0164 
0165    /// \copydoc RHistStats::ComputeNEffectiveEntries()
0166    double ComputeNEffectiveEntries() const { return fStats.ComputeNEffectiveEntries(); }
0167    /// \copydoc RHistStats::ComputeMean()
0168    double ComputeMean(std::size_t dim = 0) const { return fStats.ComputeMean(dim); }
0169    /// \copydoc RHistStats::ComputeStdDev()
0170    double ComputeStdDev(std::size_t dim = 0) const { return fStats.ComputeStdDev(dim); }
0171 
0172    /// \}
0173    /// \name Accessors
0174    /// \{
0175 
0176    /// Get the content of a single bin.
0177    ///
0178    /// \code
0179    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0180    /// std::array<ROOT::Experimental::RBinIndex, 2> indices = {3, 5};
0181    /// int content = hist.GetBinContent(indices);
0182    /// \endcode
0183    ///
0184    /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
0185    /// values. See also the class documentation of RBinIndex.
0186    ///
0187    /// Throws an exception if the number of indices does not match the axis configuration or the bin is not found.
0188    ///
0189    /// \param[in] indices the array of indices for each axis
0190    /// \return the bin content
0191    /// \par See also
0192    /// the \ref GetBinContent(const A &... args) const "variadic function template overload" accepting arguments
0193    /// directly
0194    template <std::size_t N>
0195    const BinContentType &GetBinContent(const std::array<RBinIndex, N> &indices) const
0196    {
0197       return fEngine.GetBinContent(indices);
0198    }
0199 
0200    /// Get the content of a single bin.
0201    ///
0202    /// \code
0203    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0204    /// std::vector<ROOT::Experimental::RBinIndex> indices = {3, 5};
0205    /// int content = hist.GetBinContent(indices);
0206    /// \endcode
0207    ///
0208    /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
0209    /// values. See also the class documentation of RBinIndex.
0210    ///
0211    /// Throws an exception if the number of indices does not match the axis configuration or the bin is not found.
0212    ///
0213    /// \param[in] indices the array of indices for each axis
0214    /// \return the bin content
0215    /// \par See also
0216    /// the \ref GetBinContent(const A &... args) const "variadic function template overload" accepting arguments
0217    /// directly
0218    const BinContentType &GetBinContent(const std::vector<RBinIndex> &indices) const
0219    {
0220       return fEngine.GetBinContent(indices);
0221    }
0222 
0223    /// Get the content of a single bin.
0224    ///
0225    /// \code
0226    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0227    /// int content = hist.GetBinContent(ROOT::Experimental::RBinIndex(3), ROOT::Experimental::RBinIndex(5));
0228    /// // ... or construct the RBinIndex arguments implicitly from integers:
0229    /// content = hist.GetBinContent(3, 5);
0230    /// \endcode
0231    ///
0232    /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
0233    /// values. See also the class documentation of RBinIndex.
0234    ///
0235    /// Throws an exception if the number of arguments does not match the axis configuration or the bin is not found.
0236    ///
0237    /// \param[in] args the arguments for each axis
0238    /// \return the bin content
0239    /// \par See also
0240    /// the function overloads accepting \ref GetBinContent(const std::array<RBinIndex, N> &indices) const "`std::array`"
0241    /// or \ref GetBinContent(const std::vector<RBinIndex> &indices) const "`std::vector`"
0242    template <typename... A>
0243    const BinContentType &GetBinContent(const A &...args) const
0244    {
0245       return fEngine.GetBinContent(args...);
0246    }
0247 
0248    /// Get the multidimensional range of all bins.
0249    ///
0250    /// \return the multidimensional range
0251    RBinIndexMultiDimRange GetFullMultiDimRange() const { return fEngine.GetFullMultiDimRange(); }
0252 
0253    /// Set the content of a single bin.
0254    ///
0255    /// \code
0256    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0257    /// std::array<ROOT::Experimental::RBinIndex, 2> indices = {3, 5};
0258    /// int value = /* ... */;
0259    /// hist.SetBinContent(indices, value);
0260    /// \endcode
0261    ///
0262    /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
0263    /// values. See also the class documentation of RBinIndex.
0264    ///
0265    /// Throws an exception if the number of indices does not match the axis configuration or the bin is not found.
0266    ///
0267    /// \warning Setting the bin content will taint the global histogram statistics. Attempting to access its values, for
0268    /// example calling GetNEntries(), will throw exceptions.
0269    ///
0270    /// \param[in] indices the array of indices for each axis
0271    /// \param[in] value the new value of the bin content
0272    /// \par See also
0273    /// the \ref SetBinContent(const A &... args) "variadic function template overload" accepting arguments directly
0274    template <std::size_t N, typename V>
0275    void SetBinContent(const std::array<RBinIndex, N> &indices, const V &value)
0276    {
0277       fEngine.SetBinContent(indices, value);
0278       fStats.Taint();
0279    }
0280 
0281    /// Set the content of a single bin.
0282    ///
0283    /// \code
0284    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0285    /// int value = /* ... */;
0286    /// hist.SetBinContent(ROOT::Experimental::RBinIndex(3), ROOT::Experimental::RBinIndex(5), value);
0287    /// // ... or construct the RBinIndex arguments implicitly from integers:
0288    /// hist.SetBinContent(3, 5, value);
0289    /// \endcode
0290    ///
0291    /// \note Compared to TH1 conventions, the first normal bin has index 0 and underflow and overflow bins are special
0292    /// values. See also the class documentation of RBinIndex.
0293    ///
0294    /// Throws an exception if the number of arguments does not match the axis configuration or the bin is not found.
0295    ///
0296    /// \warning Setting the bin content will taint the global histogram statistics. Attempting to access its values, for
0297    /// example calling GetNEntries(), will throw exceptions.
0298    ///
0299    /// \param[in] args the arguments for each axis and the new value of the bin content
0300    /// \par See also
0301    /// the \ref SetBinContent(const std::array<RBinIndex, N> &indices, const V &value) "function overload" accepting
0302    /// `std::array`
0303    template <typename... A>
0304    void SetBinContent(const A &...args)
0305    {
0306       fEngine.SetBinContent(args...);
0307       fStats.Taint();
0308    }
0309 
0310    /// \}
0311    /// \name Filling
0312    /// \{
0313 
0314    /// Fill an entry into the histogram.
0315    ///
0316    /// \code
0317    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0318    /// auto args = std::make_tuple(8.5, 10.5);
0319    /// hist.Fill(args);
0320    /// \endcode
0321    ///
0322    /// If one of the arguments is outside the corresponding axis and flow bins are disabled, the entry will be silently
0323    /// discarded.
0324    ///
0325    /// Throws an exception if the number of arguments does not match the axis configuration, or if an argument cannot be
0326    /// converted for the axis type at run-time.
0327    ///
0328    /// \param[in] args the arguments for each axis
0329    /// \par See also
0330    /// the \ref Fill(const A &... args) "variadic function template overload" accepting arguments directly and the
0331    /// \ref Fill(const std::tuple<A...> &args, RWeight weight) "overload for weighted filling"
0332    template <typename... A>
0333    void Fill(const std::tuple<A...> &args)
0334    {
0335       fEngine.Fill(args);
0336       fStats.Fill(args);
0337    }
0338 
0339    /// Fill an entry into the histogram with a weight.
0340    ///
0341    /// This overload is not available for integral bin content types (see \ref RHistEngine::SupportsWeightedFilling).
0342    ///
0343    /// \code
0344    /// ROOT::Experimental::RHist<float> hist({/* two dimensions */});
0345    /// auto args = std::make_tuple(8.5, 10.5);
0346    /// hist.Fill(args, ROOT::Experimental::RWeight(0.8));
0347    /// \endcode
0348    ///
0349    /// If one of the arguments is outside the corresponding axis and flow bins are disabled, the entry will be silently
0350    /// discarded.
0351    ///
0352    /// Throws an exception if the number of arguments does not match the axis configuration, or if an argument cannot be
0353    /// converted for the axis type at run-time.
0354    ///
0355    /// \param[in] args the arguments for each axis
0356    /// \param[in] weight the weight for this entry
0357    /// \par See also
0358    /// the \ref Fill(const A &... args) "variadic function template overload" accepting arguments directly and the
0359    /// \ref Fill(const std::tuple<A...> &args) "overload for unweighted filling"
0360    template <typename... A>
0361    void Fill(const std::tuple<A...> &args, RWeight weight)
0362    {
0363       fEngine.Fill(args, weight);
0364       fStats.Fill(args, weight);
0365    }
0366 
0367    /// Fill an entry into the histogram.
0368    ///
0369    /// \code
0370    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0371    /// hist.Fill(8.5, 10.5);
0372    /// \endcode
0373    ///
0374    /// For weighted filling, pass an RWeight as the last argument:
0375    /// \code
0376    /// ROOT::Experimental::RHist<float> hist({/* two dimensions */});
0377    /// hist.Fill(8.5, 10.5, ROOT::Experimental::RWeight(0.8));
0378    /// \endcode
0379    /// This is not available for integral bin content types (see \ref RHistEngine::SupportsWeightedFilling).
0380    ///
0381    /// If one of the arguments is outside the corresponding axis and flow bins are disabled, the entry will be silently
0382    /// discarded.
0383    ///
0384    /// Throws an exception if the number of arguments does not match the axis configuration, or if an argument cannot be
0385    /// converted for the axis type at run-time.
0386    ///
0387    /// \param[in] args the arguments for each axis
0388    /// \par See also
0389    /// the function overloads accepting `std::tuple` \ref Fill(const std::tuple<A...> &args) "for unweighted filling"
0390    /// and \ref Fill(const std::tuple<A...> &args, RWeight) "for weighted filling"
0391    template <typename... A>
0392    void Fill(const A &...args)
0393    {
0394       static_assert(sizeof...(A) >= 1, "need at least one argument to Fill");
0395       if constexpr (sizeof...(A) >= 1) {
0396          fEngine.Fill(args...);
0397          fStats.Fill(args...);
0398       }
0399    }
0400 
0401    /// \}
0402    /// \name Operations
0403    /// \{
0404 
0405    /// Add all bin contents and statistics of another histogram.
0406    ///
0407    /// Throws an exception if the axes configurations are not identical.
0408    ///
0409    /// \param[in] other another histogram
0410    void Add(const RHist &other)
0411    {
0412       fEngine.Add(other.fEngine);
0413       fStats.Add(other.fStats);
0414    }
0415 
0416    /// Add all bin contents and statistics of another histogram using atomic instructions.
0417    ///
0418    /// Throws an exception if the axes configurations are not identical.
0419    ///
0420    /// \param[in] other another histogram that must not be modified during the operation
0421    void AddAtomic(const RHist &other)
0422    {
0423       fEngine.AddAtomic(other.fEngine);
0424       fStats.AddAtomic(other.fStats);
0425    }
0426 
0427    /// Clear all bin contents and statistics.
0428    void Clear()
0429    {
0430       fEngine.Clear();
0431       fStats.Clear();
0432    }
0433 
0434    /// Clone this histogram.
0435    ///
0436    /// Copying all bin contents can be an expensive operation, depending on the number of bins.
0437    ///
0438    /// \return the cloned object
0439    RHist Clone() const
0440    {
0441       RHist h(fEngine.Clone());
0442       h.fStats = fStats;
0443       return h;
0444    }
0445 
0446    /// Convert this histogram to a different bin content type.
0447    ///
0448    /// There is no bounds checking to make sure that the converted values can be represented. Note that it is not
0449    /// possible to convert to RBinWithError since the information about individual weights has been lost since filling.
0450    ///
0451    /// Converting all bin contents can be an expensive operation, depending on the number of bins.
0452    ///
0453    /// \return the converted object
0454    template <typename U>
0455    RHist<U> Convert() const
0456    {
0457       RHist<U> h(fEngine.template Convert<U>());
0458       h.fStats = fStats;
0459       return h;
0460    }
0461 
0462    /// Scale all histogram bin contents and statistics.
0463    ///
0464    /// This method is not available for integral bin content types.
0465    ///
0466    /// \param[in] factor the scale factor
0467    void Scale(double factor)
0468    {
0469       fEngine.Scale(factor);
0470       fStats.Scale(factor);
0471    }
0472 
0473    /// Slice this histogram with an RSliceSpec per dimension.
0474    ///
0475    /// With a range, only the specified bins are retained. All other bin contents are transferred to the underflow and
0476    /// overflow bins:
0477    /// \code
0478    /// ROOT::Experimental::RHist<int> hist(/* one dimension */);
0479    /// // Fill the histogram with a number of entries...
0480    /// auto sliced = hist.Slice({hist.GetAxes()[0].GetNormalRange(1, 5)});
0481    /// // The returned histogram will have 4 normal bins, an underflow and an overflow bin.
0482    /// \endcode
0483    ///
0484    /// Slicing can also perform operations per dimension, see RSliceSpec. RSliceSpec::ROperationRebin allows to rebin
0485    /// the histogram axis, grouping a number of normal bins into a new one:
0486    /// \code
0487    /// ROOT::Experimental::RHist<int> hist(/* one dimension */);
0488    /// // Fill the histogram with a number of entries...
0489    /// auto rebinned = hist.Slice(ROOT::Experimental::RSliceSpec::ROperationRebin(2));
0490    /// // The returned histogram has groups of two normal bins merged.
0491    /// \endcode
0492    ///
0493    /// RSliceSpec::ROperationSum sums the bin contents along that axis, which allows to project to a lower-dimensional
0494    /// histogram:
0495    /// \code
0496    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0497    /// // Fill the histogram with a number of entries...
0498    /// auto projected = hist.Slice(ROOT::Experimental::RSliceSpec{}, ROOT::Experimental::RSliceSpec::ROperationSum{});
0499    /// // The returned histogram has one dimension, with bin contents summed along the second axis.
0500    /// \endcode
0501    /// Note that it is not allowed to sum along all histogram axes because the return value would be a scalar.
0502    ///
0503    /// Ranges and operations can be combined. In that case, the range is applied before the operation.
0504    ///
0505    /// \warning Combining a range and the sum operation drops bin contents, which will taint the global histogram
0506    /// statistics. Attempting to access its values, for example calling GetNEntries(), will throw exceptions.
0507    ///
0508    /// \param[in] sliceSpecs the slice specifications for each axis
0509    /// \return the sliced histogram
0510    /// \par See also
0511    /// the \ref Slice(const A &... args) const "variadic function template overload" accepting arguments directly
0512    RHist Slice(const std::vector<RSliceSpec> &sliceSpecs) const
0513    {
0514       bool dropped = false;
0515       RHist sliced(fEngine.SliceImpl(sliceSpecs, dropped));
0516       assert(sliced.fStats.GetNDimensions() == sliced.GetNDimensions());
0517       if (dropped || fStats.IsTainted()) {
0518          sliced.fStats.Taint();
0519       } else {
0520          sliced.fStats.fNEntries = fStats.fNEntries;
0521          sliced.fStats.fSumW = fStats.fSumW;
0522          sliced.fStats.fSumW2 = fStats.fSumW2;
0523          std::size_t slicedDim = 0;
0524          for (std::size_t i = 0; i < sliceSpecs.size(); i++) {
0525             // A sum operation makes the dimension disappear.
0526             if (sliceSpecs[i].GetOperationSum() == nullptr) {
0527                sliced.fStats.fDimensionStats[slicedDim] = fStats.fDimensionStats[i];
0528                slicedDim++;
0529             }
0530          }
0531          assert(slicedDim == sliced.GetNDimensions());
0532       }
0533       return sliced;
0534    }
0535 
0536    /// Slice this histogram with an RSliceSpec per dimension.
0537    ///
0538    /// With a range, only the specified bins are retained. All other bin contents are transferred to the underflow and
0539    /// overflow bins:
0540    /// \code
0541    /// ROOT::Experimental::RHist<int> hist(/* one dimension */);
0542    /// // Fill the histogram with a number of entries...
0543    /// auto sliced = hist.Slice(hist.GetAxes()[0].GetNormalRange(1, 5));
0544    /// // The returned histogram will have 4 normal bins, an underflow and an overflow bin.
0545    /// \endcode
0546    ///
0547    /// Slicing can also perform operations per dimension, see RSliceSpec. RSliceSpec::ROperationRebin allows to rebin
0548    /// the histogram axis, grouping a number of normal bins into a new one:
0549    /// \code
0550    /// ROOT::Experimental::RHist<int> hist(/* one dimension */);
0551    /// // Fill the histogram with a number of entries...
0552    /// auto rebinned = hist.Slice(ROOT::Experimental::RSliceSpec::ROperationRebin(2));
0553    /// // The returned histogram has groups of two normal bins merged.
0554    /// \endcode
0555    ///
0556    /// RSliceSpec::ROperationSum sums the bin contents along that axis, which allows to project to a lower-dimensional
0557    /// histogram:
0558    /// \code
0559    /// ROOT::Experimental::RHist<int> hist({/* two dimensions */});
0560    /// // Fill the histogram with a number of entries...
0561    /// auto projected = hist.Slice(ROOT::Experimental::RSliceSpec{}, ROOT::Experimental::RSliceSpec::ROperationSum{});
0562    /// // The returned histogram has one dimension, with bin contents summed along the second axis.
0563    /// \endcode
0564    /// Note that it is not allowed to sum along all histogram axes because the return value would be a scalar.
0565    ///
0566    /// Ranges and operations can be combined. In that case, the range is applied before the operation.
0567    ///
0568    /// \warning Combining a range and the sum operation drops bin contents, which will taint the global histogram
0569    /// statistics. Attempting to access its values, for example calling GetNEntries(), will throw exceptions.
0570    ///
0571    /// \param[in] args the arguments for each axis
0572    /// \return the sliced histogram
0573    /// \par See also
0574    /// the \ref Slice(const std::vector<RSliceSpec> &sliceSpecs) const "function overload" accepting `std::vector`
0575    template <typename... A>
0576    RHist Slice(const A &...args) const
0577    {
0578       std::vector<RSliceSpec> sliceSpecs{args...};
0579       return Slice(sliceSpecs);
0580    }
0581 
0582    /// \}
0583 
0584    /// %ROOT Streamer function to throw when trying to store an object of this class.
0585    void Streamer(TBuffer &) { throw std::runtime_error("unable to store RHist"); }
0586 };
0587 
0588 } // namespace Experimental
0589 } // namespace ROOT
0590 
0591 #endif