0

I mean to have a templated function that depends on a size_t template parameter. I have a "fallback" definition, placed in my sfinae.h.

template <size_t dim>
int sumVec(void) {
    return -1;
}

I already have a couple of specializations for specific values of dim, e.g. in my sfinae.cc,

template <>
int sumVec<2>(void) {
    return 2;
};

and its prototype in sfinae.h.

Now I want to define one specialization that applies for several values of dim, so I mean to avoid having to replicate it several times. I could make dim into an enum class, as done in One template specialization for several enum values

My question is Can I achieve my objective without (heavily) changing the code I have (but I could add to it)?

I tried adding code below either in the header or the source, and the compiler (gcc 10.2.0) threw an error non-class, non-variable partial specialization 'sumVec<std::enable_if<((dim == 3) || (dim == 4)), void> >' is not allowed so I am not sure I am not using the right approach or syntax, or what I asked is not allowed by the compiler.

template<size_t dim>
int sumVec<std::enable_if<dim == 3 || dim == 4>>(void)
{
    return dim;
};
  • You could probably just have one class and use `if constexpr` in its implementation, depends what you're trying to actually achieve – Alan Birtles Oct 10 '20 at 08:54
  • Not without changing sfinae.h. – bipll Oct 10 '20 at 09:01
  • @AlanBirtles - So far I don't have any class. I welcome you posting a brief example of what you have in mind. As for what I am after, it would be long to explain, and I am not certain it changes the question... I guess this should not be taken as an [XY Problem](https://en.wikipedia.org/wiki/XY_problem), I am currently interested in the posted MCVE... please let me know if it is not clear enough. – sancho.s ReinstateMonicaCellio Oct 10 '20 at 09:14
  • @bipll - See updated OP... I meant not to change it substantially. – sancho.s ReinstateMonicaCellio Oct 10 '20 at 09:20

2 Answers2

1

Function templates can't be partial specialized. You can apply SFINAE by overloading, which requires to change the primary template to avoid ambiguous calling.

// primary template overloading #1
template<size_t dim>
std::enable_if_t<dim != 3 && dim != 4, int> sumVec(void)
{
    return -1;
}

// primary template overloading #2
template<size_t dim>
std::enable_if_t<dim == 3 || dim == 4, int> sumVec(void)
{
    return dim;
}

// full specialization
template <>
int sumVec<2>(void) {
    return 2;
}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • This works, if placed everything in the header. What would the correct way to place definitions in a source, leaving only prototypes in the header? I tried declaring `inline` several combinations, but I am not getting the rationale to decide the correct one. – sancho.s ReinstateMonicaCellio Oct 10 '20 at 09:37
  • @sancho.sReinstateMonicaCellio It's not easy to accomplish. [Why can templates only be implemented in the header file?](https://stackoverflow.com/q/495021/3309790) – songyuanyao Oct 10 '20 at 09:43
  • I was aware of it, and I have actually upvoted it in the past. But I have used explicit instantiations in the source elsewhere, e.g. Moreover, here my `sumVec<2>` is defined in the source. But I could not manage to define the two `std::enable_if_t...` in the source. I guess with a suitable selection of `inline`s (which I did not get) it should work. – sancho.s ReinstateMonicaCellio Oct 10 '20 at 09:51
  • @sancho.sReinstateMonicaCellio Primary templates have to be visible in every translation unit where they're used, I think they have to be placed in hearder and included if necessary. BTW: If you place the specialization in cc file, which is not included, i.e. invisible in the translation unit then the primary template would be called instead. – songyuanyao Oct 10 '20 at 09:58
  • "Function templates can't be partial specialized." Not exactly true. You can get _some_ degree of partial specialization with `if constexpr` in the primary definition. – bipll Oct 10 '20 at 17:38
1

You can avoid template specialisations with if constexpr and just have a single instance of your class:

template <size_t dim>
int sumVec(void) {
    if constexpr (dim == 2) {
       return 2;
    }
    if constexpr (dim == 3 || dim == 4) {
       return dim;
    }
    return -1;
}
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60