用于在编译时检测对称数组的c++模板编程

c++ template programming for detecting symmetric array at compile time

本文关键字:c++ 编程 数组 对称 编译 检测 用于      更新时间:2023-10-16

例如,我在头文件中有以下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++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函数有非常严格的限制。

@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");
}

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

下面是我的路。

我已经在可变模板结构中修改了您的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;
 }

抱歉我英语不好。

这里有一个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), "!");
}

缺点是它在整个数组上进行迭代
它可以改进,但留给读者练习。