Partial member function template specialisation and data member access

后端 未结 3 554
长情又很酷
长情又很酷 2021-01-13 16:22

I have a question regarding partial specialisation of templated member functions.

Background: The goal is to compute descriptive statistics of larg

相关标签:
3条回答
  • 2021-01-13 16:35

    Personally I'd be likely to choose your option 4, after all the only part of the iterator version that actually varies with type is the logic in the "single value version"

    However another option is to write your iterator versions to receive the mean and size by reference, mean and size can then be updated without them having to be made public.

    This will also help with testing as it allows push_impl to be tested separately (although with this approach you might consider that's no longer the best name for the function)

    As an aside, it would be better for your push_impl to be templated only on iterator type, you can deduce the value type inside push_impl in the same way that you currently so in your calling example, but with only the iterator type as a parameter there's no chance of accidently calling it with the wrong value type (which might not always cause a compilation error if the value type can be converted to the type you pass as "T")

    0 讨论(0)
  • 2021-01-13 16:37

    push_impl can be made either an inner class template (if you use c++11) or a friend class template of your accumulator class (this seems like a good case for using friend declarations, since push_impl is essentially an integral part of your accumulator class implementation, separated purely for language reasons). Then you can use your option #3 (passing this to static methods of push_impl), but without making accumulator members public.

    Option #4 doesn't seem too bad either (since it avoids code duplication), but as you mentioned the performance impacts would need to be measured.

    0 讨论(0)
  • 2021-01-13 16:54

    As commented, you don't need to use partial specialization for this at all, indeed partial specialization is usually pretty easy to avoid, and preferred to avoid.

    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 is a (private) member function you don't need to do anything special any more.

    Compared to your proposed solutions, this has no extra performance cost. It's the same number of function calls, the only difference is passing a stateless type by value, which is a wholly trivial optimization for the compiler. And there's no sacrifice in encapsulation either. And slightly less boilerplate.

    0 讨论(0)
提交回复
热议问题