In C ++ model programming, how does one only specify a member function of a class?

Source: Internet
Author: User

I,When a parameter of the template classWhen it is a constant, only a member function of the special class

We know that in C ++ template programming, If we specialize in or partial to a template class, we need to rewrite all the functions in the entire template class, but these codes are usually very similar, in some cases, only one or two functions may be different. Other functions are the same. In this case, there are multiple identical codes at the same time, which is very unfavorable for us to maintain these codes. We 'd better simply specialize in the different functions.

For example, the following template class:

template<typename T, unsigned B>struct Base{    //other function    //....    void Func() { cout << "primary function" << endl; }};void test1(){    Base<int, 1> a;    a.Func();    Base<int, 16> b;    b.Func();}int main(){    test1();}

Only when B is equal to 16, the func function needs to be special, but other functions are the same in any case.

Below are some of our possible solutions:

Method 1:

template<typename T>struct Base<T, 16>{    //other function    //....    void Func() { cout << "specialization function" << endl; }};

Comments: through the special implementation, we need to rewrite all class member methods.

Method 2:

template<typename T, unsigned B>struct Base{    //other function    //....    void Func()    {        if (B == 16)        {            cout << "primary function" << endl;        }        else        {            cout << "specialization function" << endl;        }    }};

Comments: it is easy to understand but inefficient to judge during running.

Method 3:

template<typename T, unsigned B>struct Base{    //other function    //....    void Func()    {#if B!=16        cout << "primary function" << endl;#else        cout << "specialization function" << endl;#endif    }};

Comments: This method is incorrect if you try to implement it through pre-compilation. C ++ template compilation includes pre-compilation, syntax check, template instantiation, and other stages. In the pre-compilation stage, the template parameters are not instantiated yet.

Method 4:

template<typename T, unsigned B>struct Base{    //other function    //....    template<unsigned S>    struct FuncObj    {        void operator()()        {            cout << "primary function" << endl;        }    };    template<>    struct FuncObj<16>    {        void operator()()        {            cout << "specialization function" << endl;        }    };    FuncObj<B> Func;};

Comment: The member class is used to prevent special functions and the class member variable is added.

Method 5:

template<typename T, unsigned B>struct Base{    //other function    //....    template<unsigned N>    void FuncImpl()    {        cout << "primary function" << endl;    }    template<>    void FuncImpl<16>()    {        cout << "specialization function" << endl;    }    void Func()    {        FuncImpl<B>();    }};

Comment: The class member template function is specially implemented.

Method 6:

template<typename T, unsigned B>struct Base{    //other function    //....    template<unsigned N>     class Int2Type    {        enum { value = N };    };    template<unsigned V>    void FuncImpl(const Int2Type<V>)    {        cout << "primary function" << endl;    }    void FuncImpl(const Int2Type<16>)    {        cout << "specialization function" << endl;    }    void Func()    {        FuncImpl(Int2Type<B>());    }};

Comment: Convert the int value to a different type, and then implement it through function overload.

Method 7:

namespace{    template <bool,typename T,typename> struct conditional { typedef T type; };    template <typename T,typename U> struct conditional<false,T,U> { typedef U type; };}template<class T, unsigned B>struct Base{    //other function    //....    void Func ()    {        typedef typename ::conditional<B!=16, primary_t, spec_t>::type type;        Func_impl(type());    }private:    struct primary_t { };    struct spec_t    { };    void Func_impl (primary_t) { std::cout << "primary function" << std::endl; }    void Func_impl (spec_t   ) { std::cout << "specialization function" << std::endl; }};

Comment: similar to Method 6, it is implemented through function overloading.

Method 8:

namespace{    template <bool, typename T = void> struct enable_if { typedef T type; };    template <typename T> struct enable_if<true, T> {};}template<class T, unsigned B>struct Base{    //other function    //....    template <unsigned N>    typename ::enable_if<16!=N>::type        FuncImpl() { std::cout << "primary function" << std::endl; }    template <unsigned N>    typename ::enable_if<16==N>::type        FuncImpl() { std::cout << "specialization function" << std::endl; }    void Func() {        FuncImpl<B>();    }};

Comment: Using enable_if and sfinae is similar to Method 7.

We can see that according to the int value of the template parameter during compilation, the methods for rewriting a member function of the template class are diverse. In response to the above situation, I personally recommend method 2. We do not need to complicate the simple problem.

2. When a parameter of the template class is of a certain type, only a member function of the special class is allowed.

Next, let's consider another requirement. When a parameter of the template class is of a certain type, we need to specialize in one of the member functions:

template<typename T1, typename T2>struct Base{    //other function    //....    void Func() { cout << "primary function" << endl; }};void test2(){    Base<int, int> a;    a.Func();    Base<int, string> b;    b.Func();}int main(){    test2();}

The preceding template class is required. If T2 is of the string type, special rewriting of func is required. Other member functions are implemented in the same way in any case.

With the implementation experience of the above example, it is much easier for us to solve this problem.

Method 1:

template<typename T1, typename T2>struct Base{    //other function    //....    void Func()    {        if (typeid(std::string) == typeid(T2))        {            cout << "specialization function" << endl;        }        else        {            cout << "primary function" << endl;         }    }};

Comments: By using the runtime type recognition (rtti), you need to enable the relevant compilation options, which is inefficient.

Method 2:

template<typename T1, typename T2>struct Base{    //other function    //....    template<typename T>    void FuncImpl()    {        cout << "primary function" << endl;     }    template<>    void FuncImpl<string>()    {        cout << "specialization function" << endl;     }    void Func()    {        FuncImpl<T2>();    }};

Comments: It is implemented through special member functions.

Method 3:

template<typename T1, typename T2>struct Base{    //other function    //....    template<typename T>     class Type2Type    {        typedef T type;    };    template<typename T>    void FunImpl(const Type2Type<T>)    {        cout << "primary function" << endl;     }    template<typename T>    void FunImpl(const Type2Type<string>)    {        cout << "specialization function" << endl;     }    void Func()    {        FunImpl<T2>(Type2Type<T2>());    }};

Comment: implemented through function overloading.

Method 4:

template<typename T>struct IsString{    enum { value = false };};template<>struct IsString<string>{    enum { value = true };};template<typename T1, typename T2>struct Base{    //other function    //....    void Func()    {         if (IsString<T2>::value)        {            cout << "specialization function" << endl;         }        else        {            cout << "primary function" << endl;         }    }};

Comment: It is implemented by determining the type during compilation.

Method 5:

template<typename T3,  typename T4>struct must_be_same_type{    enum { ret = 0 };};template<>struct must_be_same_type<string, string>{    enum { ret = 1 };};template < typename T1,typename T2 >class Base{public:    //other function    //....    void Func()    {        if (must_be_same_type<T2, string>::ret)        {            cout << "specialization function" << endl;         }        else        {            cout << "primary function" << endl;         }    }};

Comment: it is similar to Method 4, but the implementation method is different.

Finally, I will discuss my own problems. We are writing an event Delegate class, which is roughly as follows:

template<typename return_type, typename first_type, typename second_type>class CEvent {public:    //other function    //....    return_type operator() (first_type p1, second_type p2)    {        return_type ret = return_type();        //...        //ret = invoker(p1, p2);        return ret;    }};void test3(){    CEvent<int, int, int> e1;    e1(1, 2);    CEvent<void, int, int> e2;    e2(1, 2);}int main(){    test3();}

We can see that when the return_type is void, the above Code fails to be compiled because there is no return value. Therefore, we can only specialize in this situation:

template<typename first_type, typename second_type>class CEvent<void, first_type, second_type>{public:    //other function    //....    void operator() (first_type p1, second_type p2)    {        //...        //invoker(p1, p2);        return;    }};

However, we will find that only this operator () function needs to be specially treated according to return_type, and other functions will always be the same.

The question we have now is how we can only specialize in this function.

First, we will think of the following implementation method:

template<typename T>struct IsVoid{    enum { value = false };};template<>struct IsVoid<void>{    enum { value = true };};template<typename return_type, typename first_type, typename second_type>class CEvent {public:    other function    ....    return_type operator() (first_type p1, second_type p2)    {        if (IsVoid<return_type>::value)        {            cout << "return type is void" << endl;            //...            //invoker(p1, p2);        }        else        {            cout << "return type is not void" << endl;            return_type ret = return_type();            //...            //ret = invoker(p1, p2);            return ret;        }    }};

However, we will soon find that the if statement is compiled in this case, so if return_type is void, the compilation will still fail.

The problem we need to solve is how to convert this If statement into a function overload, so we think of the following implementation:

template<typename T>struct IsVoid{    enum { value = false };};template<>struct IsVoid<void>{    enum { value = true };};template<int v>class Int2Type{    enum { value = v };};template<typename return_type, typename first_type, typename second_type>class CEvent {public:    //other function    //....    return_type InvokerImpl(first_type p1, second_type p2, Int2Type<true>)    {        cout << "return type is void" << endl;        //...        //invoker(p1, p2);    }    return_type InvokerImpl(first_type p1, second_type p2, Int2Type<false>)    {        cout << "return type is not void" << endl;        return_type ret = return_type();        //...        //ret = invoker(p1, p2);        return ret;    }    return_type operator() (first_type p1, second_type p2)    {        return InvokerImpl(p1, p2, Int2Type<IsVoid<return_type>::value>());    }};

The above implementation first uses the type recognition during compilation, and then converts the corresponding bool value to different types after the recognition, and then uses different types of function overloading for implementation.

Finally, we can see that C ++ is so complex that it is speechless from the Compilation Time To the runtime, from the object-oriented programming to the general model programming to the template metaprogramming, it is also powerful and speechless, and the C ++ language itself is constantly evolving (C ++ 11). The same problem often has multiple solutions in C ++, these solutions are simple, complex, efficient, and inefficient. Our goal is to use the C ++ tool to find a simple and efficient solution.

Note: I am a beginner in C ++ templates programming. If you have any errors, please correct me.

References: http://bbs.csdn.net/topics/390116038

Http://bbs.csdn.net/topics/270041821

Original Source: http://www.cnblogs.com/weiym/archive/2013/02/14/2912563.html

(Some code or text have been compiled or modified by myself)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.