SFINAE о перегрузке элементов шаблона
Я хотел бы специализировать getVector
функцию-член, я пытаюсь использовать SFINAE для этого. Но это работает только в том случае, если Dim равен 3 или больше.
template <size_t Dim>
class Mat
{
...
template <size_t VDim, typename enable_if<(Dim > 1 && VDim == 0)>::type* = nullptr>
void getVectorBegin(const array<size_t, Dim - 1>& indexAfter) const;
template <size_t VDim, typename enable_if<(Dim > 2 && 0 < VDim && VDim < Dim-1)>::type* = nullptr>
void getVectorBegin(const array<size_t, VDim>& indexBefore, const array<size_t, Dim - VDim - 1>& indexAfter) const;
template <size_t VDim, typename enable_if<(Dim > 1 && VDim == Dim-1)>::type* = nullptr>
void getVectorBegin(const array<size_t, Dim - 1>& indexBefore) const;
};
Mat<3> m;
Mat<2> m; // error C2039: 'type': is not a member of 'std::enable_if<false,_Ty>'
1 ответ:
Это будет непросто.
Я считаю, что ваш код подходит дляDim>=2
, но он плохо сформирован, когда задан аргументDim<=1
, не требующий диагностики, но по другой причине, на которую жалуется ваш компилятор.
Для
Dim>=2
это правильно, но ваш компилятор (MSVC++ я думаю) жалуется в случаеDim==2
. Учитывая описание ошибки, я полагаю, что причина заключается в том, что он ошибочно закорачивает выражения && в условияхenable_if
, интерпретируя их как значение зависит только от параметра шаблона класса, когдаDim > x
равно false. Обходной путь состоит в том, чтобы переместить проверкиDim > x
в качестве последнего члена выражения&&.Чтобы уточнить, ситуация концептуально похожа на следующий фрагмент кода:
template <size_t N> class foo { template <typename E = enable_if_t<(N>0)>> void bar(); }; foo<1> f1; foo<0> f0; // fails
Здесь инстанцирование
foo
запускает инстанцирование деклараций (но не определений) его членов (см. [temp.инст]#1); но, только проверки имен и выражений, которые зависимые от члена параметры шаблона откладываются в соответствующих точках их создания. Здесь имя типаenable_if_t<(N>0)>
Независит от любого параметра шаблонаbar()
(N
принадлежит списку параметров шаблонаfoo
), следовательно, не зависит, что приводит кenable_if<false>::type
, КогдаN == 0
, поэтому ошибка.
Возвращаясь к вашему коду, рассмотрим:[темп.отдел.constexpr]#1 за исключением того, что описано ниже, постоянное выражение является зависимый от значения , если любое подвыражение является зависимым от значения
И нигде операторы короткого замыкания не упоминаются в качестве исключения. Таким образом, выражение, скажем,
Dim > 1 && VDim == 0
зависит от значения, даже еслиDim<=1
; следовательно, ошибка не должна возникать до заменыVDim
(где SFINAE будет применяться). Фактически, и gcc, и clang соглашаются принять ваш код.Тем не менее, когда
Dim<=1
Первая и третьяgetVectorBegin
перегрузки фактически объявляют функционально эквивалентные шаблоны элементов (см. [temp.над.Ссылка]#6), поэтому я считаю, что в таком случае это неправильно.