【问题标题】:c++ template programming for detecting symmetric array at compile time用于在编译时检测对称数组的 c++ 模板编程
【发布时间】:2016-11-26 15:07:09
【问题描述】:

比如我在头文件中有如下c++代码

struct Data {
    static const int N = 4;
    static const int A[N];
};

并在其cpp文件中定义了数组A的以下内容。

const int Data::A[Data::N] = {1,2,2,1};

有没有办法编写模板来检测数组A 的内容在编译时是否对称? (可能 c++11 特性支持,但我不熟悉它的特性......)

例如,如果 A 的内容是 {1,2,2,1}false ,则 DetectSymmetric<Data>::is_sym 将是 true ,如果它等于 {1,2,3,4}

【问题讨论】:

    标签: c++ arrays templates c++11


    【解决方案1】:

    在 C++11/14 中,您可以使用 constexpr 函数:

    const int A[4] = { 1,2,2,1 };
    
    
    template<int N>
    constexpr bool symmetric_helper( const int (&a)[N], int idx) {
        return idx > 0 ? symmetric_helper<N>(a, idx - 1) && (a[idx - 1] == a[N - idx]) : true;
    }
    template<int N>
    constexpr bool symmetric(const int (&a)[N]) {
        return symmetric_helper<N>(a, N / 2);
    }
    
    std::cout << symmetric(A) << std::endl;
    

    使用 C++14,您可以编写一个简单的 for 循环而不是递归,但 C++11 对 constexpr 函数有非常严格的限制。

    【讨论】:

    • sizeof(a) == sizeof(const int*).
    • 另外,我猜你的意思不是symmetric_helper,而不是symmetric_inside
    • const int (&amp;a)[N] 使sizeof(a) 再次变为N*sizeof(int),并避免不必要的复制。
    【解决方案2】:

    @Dutow 是第一个给出有效答案的人,但这也应该考虑类型推导并能够处理任何类型的数组。

    #include <cstddef>
    
    template<typename T, size_t N, size_t O, size_t I>
    struct detect_symmetric_array
    {
        static constexpr bool is_symmetric(T (&array)[N])
        {
            return array[O] == array[N - O - 1] && detect_symmetric_array<T, N, O + 1, I - 1>::is_symmetric(array);
        }
    };
    
    template<typename T, size_t N, size_t O>
    struct detect_symmetric_array<T, N, O, 1>
    {
        static constexpr bool is_symmetric(T(&array)[N])
        {
            return array[O] == array[N - O - 1];
        }
    };
    
    template<typename T, size_t N>
    constexpr bool is_symmetric_array(T (&array)[N])
    {
        return detect_symmetric_array<T, N, 0, N / 2>::is_symmetric(array);
    }
    
    int main(int argc, char** argv)
    {
        constexpr int first[4] = { 1, 2, 2, 1 }, second[4] = { 1, 2, 3, 4 }, third[5] = {1, 2, 3, 2, 1}, foruth[5] = {1,3,2,4,5};
        static_assert(is_symmetric_array(first), "array first should be symmetric");
        static_assert(is_symmetric_array(second) == false, "array second should not be symmetric");
        static_assert(is_symmetric_array(third), "array third should be symmetric");
        static_assert(is_symmetric_array(foruth) == false, "array fourth should not be symmetric");
    }
    

    【讨论】:

      【解决方案3】:

      有很多模式可以满足您的要求。

      以下是我的方式。

      我已经在可变参数模板结构中修改了你的 Data 结构;只是为了简化示例。

      template <int ... Is>
      struct Data
       {
         static constexpr int N { sizeof...(Is) };
         static constexpr int A[N] { Is... };
       };
      
      
      template <typename T, int P1 = 0, int P2 = T::N-1, bool B = (P1 < P2)>
      struct is_sym;
      
      template <typename T, int P1, int P2>
      struct is_sym<T, P1, P2, false>
       { constexpr static bool value = true; };
      
      template <typename T, int P1, int P2>
      struct is_sym<T, P1, P2, true>
       {
         constexpr static bool value
           = (T::A[P1] == T::A[P2]) && is_sym<T, P1+1, P2-1>::value ;
       };
      
      
      int main ()
       {
         static_assert(is_sym<Data<1, 2, 3, 4>>::value == false,   "!");
         static_assert(is_sym<Data<1, 2, 2, 1>>::value == true,    "!");
         static_assert(is_sym<Data<1, 2, 3, 2, 1>>::value == true, "!");
      
         return 0;
       }
      

      ps:对不起,我的英语不好。

      【讨论】:

        【解决方案4】:

        这是一个 C++14 解决方案(最小的工作示例):

        #include<functional>
        #include<cstddef>
        
        struct Data {
            static const int N = 4;
            static constexpr int A[N] = {1,2,2,1};
            static constexpr int B[N] = {1,1,3,1};
        };
        
        template<typename T, std::size_t... I>
        constexpr bool f(const T *data, std::index_sequence<I...>) {
            bool eq = true;
            int arr[] = { (eq &= (data[I] == data[sizeof...(I)-I-1]), 0)... };
            return eq;
        }
        
        template<typename T, std::size_t N>
        constexpr bool f(const T(&data)[N]) {
            return f(data, std::make_index_sequence<N>());
        }
        
        int main() {
            static_assert(f(Data::A), "!");
            static_assert(not f(Data::B), "!");
        }
        

        缺点是它会遍历整个数组。
        它可以改进,但留给读者作为练习。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-31
          • 1970-01-01
          • 2012-02-13
          相关资源
          最近更新 更多