Reputation: 19023
I would like to specialize getVector
member function, i'm trying to use SFINAE for this. But it works only if Dim is 3 or greater.
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>'
Upvotes: 2
Views: 165
Reputation: 5624
This is going to be tricky.
I believe your code is ok for Dim>=2
but it's ill-formed when given a Dim<=1
argument, with no diagnostic required, but for a different reason your compiler is complaining about.
For Dim>=2
it is correct, but your compiler (MSVC++ I guess) complains in the Dim==2
case. Given the error description, I suppose the reason is that it's erroneously short-circuiting the && expressions in the enable_if
conditions, interpreting them as value-dependent only on the class template parameter when Dim > x
is false. The workaround is to move the Dim > x
checks as the last term of the && expression.
To elaborate, the situation is conceptually similar to the following code snippet:
template <size_t N>
class foo
{
template <typename E = enable_if_t<(N>0)>>
void bar();
};
foo<1> f1;
foo<0> f0; // fails
here, the instantation of foo
triggers the instantiation of the declarations (but not the definitions) of its members (see [temp.inst]#1); but, only checks of names and expressions that depend on the member template parameters are postponed at their respective instantiation points. Here, the type name enable_if_t<(N>0)>
does not depend on any bar()
template parameter (N
belongs to foo
's template parameters list) hence is non-dependent, resulting in enable_if<false>::type
when N == 0
, so the error.
Going back to your code, consider:
[temp.dep.constexpr]#1 Except as described below, a constant expression is value-dependent if any subexpression is value-dependent
and nowhere shortcircuiting operators are mentioned as an exception. So, the expression, say, Dim > 1 && VDim == 0
is value-dependent even if Dim<=1
; therefore, no error should occur until substitution of VDim
(where SFINAE would apply). In fact, both gcc and clang agree on accepting your code.
That said, when Dim<=1
the first and third getVectorBegin
overloads actually declare functionally equivalent member templates (see [temp.over.link]#6), so I believe it's ill-formed in that case.
Upvotes: 2