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

时间:2014-04-28 22:54:04

标签: c++ c++11

我有以下模板:

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是非数组类型时,Array模板才有效。

1 个答案:

答案 0 :(得分:4)

可能有点矫枉过正,但你可以强迫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的数组类型,则需要对其进行更多处理。