c++ - 除非满足静态条件,否则阻止转换运算符编译

标签 c++ templates c++11 sfinae

我有 Vector ( CVector<T, std::size_t Size> )、Matrix ( CMatrix<T, std::size_t Height, std::size_t Width> ) 和 Tensor ( CTensor<T, std::size_t... Sizes> ) 类,我希望能够从 CTensor 隐式转换类到 CVector如果 sizeof...(Sizes) == 1 类和 CMatrix如果 sizeof...(Sizes) == 2 类,所以我有以下转换运算符(最初我没有 std::enable_if 模板参数希望我可以使用 SFINAE 来防止它编译):

template <typename std::enable_if<sizeof...(Sizes) == 2, int>::type = 0>
operator CMatrix<NumType, Sizes...>() const
{
    static_assert(sizeof...(Sizes) == 2, "You can only convert a rank 2 tensor to a matrix");

    CMatrix<NumType, Sizes...> matResult;

    auto& arrThis = m_numArray;
    auto& arrResult = matResult.m_numArray;
    concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<2> index ) restrict( amp ) {
        arrResult[index] = arrThis[index];
    } );

    return matResult;
}

template <typename std::enable_if<sizeof...(Sizes) == 1, int>::type = 0>
operator CVector<NumType, Sizes...>() const
{
    static_assert(sizeof...(Sizes) == 1, "You can only convert a rank 1 tensor to a vector");

    CVector<NumType, Sizes...> vecResult;

    auto& arrThis = m_numArray;
    auto& arrResult = vecResult.m_numArray;
    concurrency::parallel_for_each( arrResult.extent, [=, &arrThis, &arrResult]( concurrency::index<1> index ) restrict( amp ) {
        arrResult[index] = arrThis[index];
    } );

    return vecResult;
}

但是,如果我实例化 CTensor<float, 3, 3, 3>例如,尝试编译时,我会收到错误消息,声明 CMatrix 的模板参数过多。和 CVector以及有关 std::enable_if<false, int> 类型缺失的错误.有没有一种方法可以实现这些运算符而无需专门化 CTensor对于排名 1 和 2?

最佳答案

我已经简化了之前的解决方案,详情如下。

根本不需要 SFINAE,因为模板方法中有 static_assert,它仅在使用时实例化。

我的解决方案使转换运算符成为具有相关参数 的模板方法(以便编译器不实例化其主体,仅解析签名),并添加 -1 大小假装在大小为 1 的张量内缺少维度(不是张量本身,而是提取参数包的辅助类),以允许编译器实例化张量模板本身,但不允许稍后实例化张量内的转换运算符无效维度。

Live demo link.

#include <cstddef>

template <typename T, unsigned int index, T In, T... args>
struct GetArg
{
    static const T value = GetArg<T, index-1, args...>::value;
};

template <typename T, T In, T... args>
struct GetArg<T, 0, In, args...>
{
    static const T value = In;
};

template <typename T, T In>
struct GetArg<T, 1, In>
{
    static const T value = -1;
};

template <typename T, std::size_t Size>
struct CVector
{
};

template <typename T, std::size_t Height, std::size_t Width>
struct CMatrix
{
};

template <typename T, std::size_t... Sizes>
struct CTensor 
{
    template <std::size_t SZ = sizeof...(Sizes)>
    operator CVector<T, GetArg<std::size_t, 0, Sizes...>::value>() const
    {
        static_assert(SZ == 1, "You can only convert a rank 1 tensor to a vector");
        CVector<T, Sizes...> vecResult;
        return vecResult;
    }

    template <std::size_t SZ = sizeof...(Sizes)>
    operator CMatrix<T, GetArg<std::size_t, 0, Sizes...>::value, GetArg<std::size_t, 1, Sizes...>::value>() const
    {
        static_assert(SZ == 2, "You can only convert a rank 2 tensor to a matrix");
        CMatrix<T, Sizes...> matResult;
        return matResult;
    }
};

int main()
{
    CTensor<float, 3> tensor3;
    CTensor<float, 3, 3> tensor3_3;
    CTensor<float, 3, 3, 3> tensor3_3_3;
    CVector<float, 3> vec(tensor3);
    //CVector<float, 3> vec2(tensor3_3); // static_assert fails!
    CMatrix<float, 3, 3> mat(tensor3_3);
    //CMatrix<float, 3, 3> mat2(tensor3_3_3); // static_assert fails!
}

关于c++ - 除非满足静态条件,否则阻止转换运算符编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25584540/

相关文章:

c++ - 将二维数组传递给函数时出错

c++ - 如何使用 C++ 11 创建计时器事件?

c++ - 使用 C++11 占位符作为 lambdas?

c++ - exchange 或 compare_and_exchange 是否读取修改顺序中的最后一个值?

c++处理irc bot的recv函数中的多个字符串

c++ - 有什么方法可以在打开应用程序的 VS 中将批处理文件作为构建后事件运行?

C++ 在 Linux 上编写 UTF-8

c++ - 为什么这些函数模板与实例化都不匹配?

c++ - 如何根据 operator() 参数泛化一个类?

c++ - 具有模板化参数的函数指针歧义