避免模棱两可的部分专业化

Avoid ambiguous partial specialization

本文关键字:专业化 模棱两可      更新时间:2023-10-16

我有以下模板:

template<typename T, typename S=void>
struct Array;
template<typename T, int N0, int N1, int S0, int S1>
struct Array<T[N0][N1], T[S0][S1]> {};
template<typename T, int N0, int N1>
struct Array<T[N0][N1], void> : Array<T[N0][N1], T[N1][1]> {};
template<typename T, int N0, int N1, int N2, int S0, int S1, int S2>
struct Array<T[N0][N1][N2], T[S0][S1][S2]> {
  template<int B0, int E0, int B1, int E1, int B2, int E2>
  Array<T[E0 - B0][E1 - B1][E2 - B2], T[S0][S1][S2]>
  get() {
    return Array<T[E0 - B0][E1 - B1][E2 - B2], T[S0][S1][S2]>();
  }
};
template<typename T, int N0, int N1, int N2>
struct Array<T[N0][N1][N2], void> : Array<T[N0][N1][N2], T[N1 * N2][N2][1]> {};
int main() {
  Array<float[3][4][4], float[16][4][1]> a;
  auto b = a.get<0, 2, 0, 2, 0, 1>();
  return 0;
}

由于模板的部分专业化不明确,我得到了以下错误:

$ clang++ -std=c++11 main.cpp && ./a.out
main.cpp:26:14: error: ambiguous partial specializations of 'Array<float [2][2][1],     float [16][4][1]>'
  auto b = a.get<0, 2, 0, 2, 0, 1>();
         ^
main.cpp:5:8: note: partial specialization matches [with T = float [1], N0 = 2, N1 = 2, S0 = 16, S1 = 4]
struct Array<T[N0][N1], T[S0][S1]> {};
       ^
main.cpp:11:8: note: partial specialization matches [with T = float, N0 = 2, N1 = 2, N2 = 1, S0 = 16, S1 = 4, S2 = 1]
struct Array<T[N0][N1][N2], T[S0][S1][S2]> {
       ^
1 error generated.

有什么方法可以避免这种歧义吗?换句话说,我希望只有当T是非数组类型时,数组模板才有效。

这可能有些过头了,但您可以强制T不是数组:

#include <type_traits>
template<typename T, typename S = void, typename Dummy = void>
struct Array;
template<typename T, int N0, int N1, int S0, int S1>
struct Array<T[N0][N1],
             T[S0][S1],
             typename std::enable_if<!std::is_array<T>::value>::type>
{ };
template<typename T, int N0, int N1>
struct Array<T[N0][N1],
             void,
             typename std::enable_if<!std::is_array<T>::value>::type>
: Array<T[N0][N1], T[N1][1]>
{ };
template<typename T, int N0, int N1, int N2, int S0, int S1, int S2>
struct Array<T[N0][N1][N2],
             T[S0][S1][S2],
             typename std::enable_if<!std::is_array<T>::value>::type>
{
    template<int B0, int E0, int B1, int E1, int B2, int E2>
    Array<T[E0 - B0][E1 - B1][E2 - B2], T[S0][S1][S2]>
    get()
    {
        return {};
    }
};

如果您真的想允许T使用数组类型,那么还需要进一步研究。