代码之家  ›  专栏  ›  技术社区  ›  Nick

std::获取类(部分)模板专门化

  •  1
  • Nick  · 技术社区  · 7 年前

    我有课 复数

    template<typename T>
    struct Complex{
        T r;
        T i;
    };
    

    我决定添加类似于 std::get :

    template<int X, typename T>
    T get(const Complex<T> &a){
       switch(X){
           case 0: return a.r;
           case 1: return a.i;
       }
    }
    

    这行得通。我也知道编译器可以优化它。

    template<int X,typename T>
    T get(const Complex<T> &a);
    
    template<typename T>
    constexpr T get<0, T>(const Complex<T> &a){
        return a.r;
    }
    
    template<typename T>
    constexpr T get<1, T>(const Complex<T> &a){
        return a.i;
    }
    

    但这并不能编译,我很好奇如何正确实现?

    我试着检查 标准::获取

    4 回复  |  直到 7 年前
        1
  •  1
  •   Maxim Egorushkin    7 年前

    函数模板不能部分专业化。

    另一种方法是 使用函数重载实现类似效果:

    template<int X>
    using Int = std::integral_constant<int, X>;
    
    template<typename T> inline T get(const Complex<T> &a, Int<0>) { return a.r; }
    template<typename T> inline T get(const Complex<T> &a, Int<1>) { return a.i; }
    
    template<int X, typename T>
    inline T get(const Complex<T> &a) { return get(a, Int<X>{}); }
    
        2
  •  3
  •   Mike Kinghan Luchian Grigore    7 年前

    在C++ 11中,你可以像这样执行这个练习:

    #include <type_traits>
    
    template<typename T>
    struct Complex{
        T r;
        T i;
    };
    
    
    template<int X, typename T>
    constexpr typename std::enable_if<X == 0,T>::type
    get(const Complex<T> &a){
        return a.r;
    }
    
    template<int X, typename T>
    constexpr typename std::enable_if<X == 1,T>::type
    get(const Complex<T> &a){
        return a.i;
    }
    

    Live demo

    Partial template specialization 类模板,而不是函数模板。

    std::enable_if_t

    在C++ 17中,你可以使用 if constexpr 编写单个函数模板而不是

        3
  •  0
  •   Nick    7 年前

    我能想到这个,但对于这么简单的任务来说,它看起来非常复杂:

    namespace complex_impl__{
        template<int X, typename T>
        struct GetHelper{
            static T get(const Complex<T> &a);
        };
    
        template<typename T>
        struct GetHelper<0, T>{
            constexpr static T get(const Complex<T> &a){
                return a.r;
            }
        };
    
        template<typename T>
        struct GetHelper<1, T>{
            constexpr static T get(const Complex<T> &a){
                return a.i;
            }
        };
    }
    
    template<int I,typename T>
    constexpr T get(const Complex<T> &a){
        return complex_impl__::GetHelper<I, T>::get(a);
    }
    

    T 进入之内 get()

    namespace complex_impl__{
        template<int I>
        struct GetHelper{
            template<typename T>
            static T get(const Complex<T> &a);
        };
    
        template<>
        struct GetHelper<0>{
            template<typename T>
            constexpr static T get(const Complex<T> &a){
                return a.r;
            }
        };
    
        template<>
        struct GetHelper<1>{
            template<typename T>
            constexpr static T get(const Complex<T> &a){
                return a.i;
            }
        };
    }
    
    template<int I,typename T>
    constexpr T get(const Complex<T> &a){
        return complex_impl__::GetHelper<I>::get(a);
    }
    

    template<int I> struct GetHelper

    namespace complex_impl__{
        template<int I>
        struct GetHelper;
    
        template<>
        struct GetHelper<0>{
            template<typename T>
            constexpr static T get(const Complex<T> &a){
                return a.r;
            }
        };
    
        template<>
        struct GetHelper<1>{
            template<typename T>
            constexpr static T get(const Complex<T> &a){
                return a.i;
            }
        };
    }
    
    template<int I,typename T>
    constexpr T get(const Complex<T> &a){
        return complex_impl__::GetHelper<I>::get(a);
    }
    
        4
  •  0
  •   Johnathan Jacobs    7 年前

    问题是不能部分地专门化函数模板。请阅读 C++ template specialisation of function Getting “illegal use of explicit template arguments” when doing a pointer partial specialization for a class method ,尼克描述了相同的解决方案。

    你的解决方案看起来不错, 我只要把开关换成 if constexpr

    #include <iostream>
    
    template<typename T>
    struct Complex 
    {
        T r;
        T i;
    };
    
    template<int X, typename T>
    constexpr T get(const Complex<T> &a)
    {
        if constexpr(X == 0)
        {
            return a.r;
        }
        else if constexpr (X == 1)
        {
            return a.i;
        }
    }
    
    int main()
    {
        Complex<int> test;
        test.r = 1;
        test.i = 12;
    
        std::cout << get<0>(test) << std::endl;
        std::cout << get<1>(test) << std::endl;
    
        std::cin.get();
    
    }