代码之家  ›  专栏  ›  技术社区  ›  Yves Daoust

基于类型具有不同定义的模板函数

  •  0
  • Yves Daoust  · 技术社区  · 6 年前

    假设我们有具有不同成员类型和计数的不同类(结构)。为了示例起见,它们是二维和三维向量。

    struct i2 { 
        int a, b; 
        i(int a, int b): a(a), b(b) {}
    };
    
    struct f2 { 
        float a, b;
        f(float a, float b): a(a), b(b) {}
    };
    
    struct i3 { 
        int a, b, c; 
        i(int a, int b): a(a), b(b), c(c) {}
    };
    
    struct f3 { 
        float a, b, c;
        f(float a, float b): a(a), b(b), c(c) {}
    };
    

    我想以模板化的方式实现一些相关的函数。在类之外说一个加法运算符,比如

    template<class Type> Type operator+(const Type& P, const& Type Q)
      { return Type(P.a + Q.b, P.a + P.b); }
    

    显然,这对3d变体不起作用,这需要

    template<class Type> Type operator+(const Type& P, const Type& Q)
      { return Type(P.a + Q.a, P.b + P.b, P.c + Q.c); }
    

    有没有一个很好的方法来实现这一点,而不需要很多明确的专业化?如果使用高级C++特性,支持它的最小版本是什么?

    换句话说,是否有编译时机制根据参数类型有条件地实例化模板?

    请注意,我希望初始类保持非模板化,因为这会在我的设计中引入其他问题。

    2 回复  |  直到 6 年前
        1
  •  1
  •   Jarod42    6 年前

    一旦你有了自己的特点,你就可以使用sfinae。

    可以在任何版本的C++中完成特性,即使使用较新版本也更容易。

    根据你想如何定义你的特质,你可以使用

    template <typename T>
    using is_2d_vector = std::disjunction_t<std::is_same<T, i2>, std::is_same<T, f2>>;
    
    template <typename T>
    using is_3d_vector = std::disjunction_t<std::is_same<T, i3>, std::is_same<T, f3>>;
    
    // possible alternatives include detection of T::a, T::b, T::c
    
    template<class T, std::enable_if_t<is_2d_vector<T>, int> = 0>
    T operator+(const T& lhs, const T& rhs)
    { return T(lhs.a + rhs.a, lhs.b + rhs.b); }
    
    template<class T, std::enable_if_t<is_3d_vector<T>, int> = 0>
    T operator+(const T& lhs, const T& rhs)
    { return T(lhs.a + rhs.a, lhs.b + rhs.b, lhs.c + rhs.c); }
    

    但模板类最初看起来更简单:

    template <typename T>
    struct T2 { 
        T a, b;
        T2(T a, T b): a(a), b(b) {}
    
        friend operator +(const T2& lhs, const T2& rhs)
        { return T(lhs.a + rhs.a, lhs.b + rhs.b); }
    };
    
    template <typename T>
    struct T3 { 
        T a, b, c; 
        T3(T a, T b, T c): a(a), b(b), c(c) {}
    
        friend operator +(const T2& lhs, const T2& rhs)
        { return T(lhs.a + rhs.a, lhs.b + rhs.b, lhs.c + rhs.c); }
    };
    
    using i2 = T2<int>;
    using i3 = T3<int>;
    using f2 = T2<float>;
    using f3 = T3<float>;
    
        2
  •  0
  •   CS Pei    6 年前

    我认为一种方法是使用编译时(静态)反射。网上有不少文章,这里有两篇, https://medium.com/@vesko.karaganev/compile-time-reflection-in-c-17-55c14ee8106b https://Frly.sexy/post/basic-reflection-in-pure-cpp17

    但我不确定这是解决你问题的最好方法,因为更好的答案需要更具体的细节。