2

我正在编写一个模板化的 GPGPU 张量求和函数(主要是为了好玩,也是为了加深我对模板元编程和 GPGPU 编程的理解),我想做一些静态断言来防止函数的无效使用。

C++ AMP 类的要求之一array_view是它是矩形的(即所有范围都相同)。

但是,我不完全确定如何做到这一点。目前我的功能看起来像:

template <typename T, typename U>
auto TensorSum( T t, U u )->decltype( std::remove_all_extents<T>::type + std::remove_all_extents<U>::type )
{
    using SumType = decltype(std::remove_all_extents<T>::type + std::remove_all_extents<U>::type);

    static_assert( std::rank<T>::value == std::rank<U>::value, "The two tensors must have the same rank" );

    // ToDo: Put a static assertion here to ensure tensors are rectangular

    SumType arrSum[std::rank<T>::value * std::extent<U>::value];

    concurrency::array_view<std::remove_all_extents<T>::type, std::rank<T>::value> a( std::extent<T>::value, t );
}

我的主要问题是排名是一个变量,无法在编译时执行迭代。

4

2 回答 2

0

这样做的唯一方法是也制作类模板的值(我使用了不同的示例)

template <typename T, typename U, T t, U u>
void blah()
{
  static_assert(t==u,"sizes must be equal");
  printf("foo");
}
int main()
{
  blah<int,int,10,10>();
  //blah<int,int,10,15>();error C2338 (Visual Studio): "sizes must be equal"
}

我最近以这种方式制作了一个矩阵类:

template <size_t M,size_t N>
class Matrix
{
    double values_[M][N];
    ...

};

而不是操作员像这样工作:

 template <size_t M, size_t N>
 operator +(const Matrix<M,N>& lhs,const Matrix<M,N>& rhs){...}

因为大小是类型的一部分,所以很容易使运算符仅适用于类似的有效情况。但是,替代方案是:

 template <size_t ML, size_t NL,size_t MR,size_t NR>
 operator +(const Matrix<ML,NL>& lhs,const Matrix<MR,NR>& rhs)
 {
    static_assert(ML==MR && NL==NR,"Matrix dimensions must aggree");
     ...
 }

两种方法都可以,但是如果您不将大小与某种模板参数相关联,则只能进行运行时检查(AKA 异常处理)。

于 2013-07-29T17:23:39.733 回答
0

以下boost::mpl代码将按照您的要求执行。
关键是将你的循环重新定义为一个累积和调用boost::mpl::fold

    #include <boost/mpl/range_c.hpp>
    #include <boost/mpl/fold.hpp>
    #include <boost/mpl/int.hpp>
    #include <boost/mpl/bool.hpp>
    #include <boost/mpl/and.hpp>
    template <class T>
    struct is_rectangular
    {
        struct rectangular_check
        {
            template <class Value, class Dim>
            struct apply
            {
                typedef typename and_<
                    Value,
                    bool_<std::extent<T>::value == std::extent<T, Dim::value>::value>
                    >::type type;
            };
        };

        typedef typename fold<
            range_c<
                unsigned,
                0,
                std::rank<T>::value
                >,
            true_,
            rectangular_check
            >::type type;
    };

所以现在你的函数(我已经修改为接受原始数组类型)看起来像:

    template <typename T, typename U>
    auto TensorSum(const T & t, const U &u )->
        decltype(std::declval<typename std::remove_all_extents<T>::type>() +
                 std::declval<typename std::remove_all_extents<U>::type>())
    {
        using SumType = decltype(std::declval<typename std::remove_all_extents<T>::type>() +
                                 std::declval<typename std::remove_all_extents<U>::type>());
        static_assert(std::rank<T>::value == std::rank<U>::value,
                      "The two tensors must have the same rank");

        // ToDo: Put a static assertion here to ensure tensors are rectangular
        std::cout << std::rank<T>::value << ' ' << std::extent<T>::value << std::endl;
        static_assert(is_rectangular<T>::type::value, "First tensor is not rectangular");
        static_assert(is_rectangular<U>::type::value, "Second tensor is not rectangular");

        SumType arrSum[std::rank<T>::value * std::extent<U>::value];
    }

    int main()
    {
        int a[10][10];
        TensorSum(a, a);
        return 0;
    }

a如果您根据需要将in的尺寸更改为不同的尺寸,这将无法编译main

这当然可以在没有 boost 帮助的情况下编写,但我更喜欢尽可能使用它。

于 2013-07-29T17:57:44.703 回答