2

The next level of template programming (beyond very simple use) has eluded me for months as I work on a specific project I've been working on. I've tried scores of methods, cutting and pasting from StackOverflow as well as trying to understand and roll my own, with no breakthroughs. A few of the techniques I've tried hit a roadblock at SFINAE with std::enable_if<>, so I've distilled the issue down and ask about that.

Let's start with a baseline template:

template<typename T>
struct foo
{
    string bar(const T& val);
};

Then specialize it for a vector of ints:

template<>
struct foo<vector<int> >
{
    string bar(vector<int> c);
};

This compiles and utilizes the correct templates from the type, as expected. But I need to be able to have more control over which templates are used.

The best I can understand from the C++ reference and numerous other sites, if I add std::enable_if<> to the mix (utilizing the enable_if_t<> alias), the following should give me the exact same behavior, replacing the std::enable_if_t<true, vector<int> > with just vector<int>:

template<>
struct foo<std::enable_if_t<true, vector<int> > >
{
    string bar(vector<int> c);
};

And it works, compiling and running as expected.

However, if I instead use partial specialization, things work differently. Without std::enable_if<>, this works as well:

template<typename T>
struct foo<vector<T> >
{
    string bar(vector<T> c);
};

But adding in std::enable_if<true, vector<T> > fails. I would expect it to replaced with vector<T>, which worked above:

template<typename T>
struct foo<std::enable_if_t<true, vector<T> > >
{
    string bar(vector<T> c);
};

But this gives me a compile time error:

test.cpp:48:8: error: template parameters not deducible in partial specialization:
  463 | struct foo<std::enable_if_t<true, vector<T> > >
      |        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:48:8: note:         ‘T’

I understand that this is partial specialization. But, so was the previous version, without the std::enable_if<>. Obviously, there is something different, but debugging templates is pretty opaque, and no amount of googling has led me to a clue. So it's not clear to me what is different, or how to get the compiler to handle this the same as without std::enable_if<>.

Please note that the end goal is to replace the vector with templated types in other containers, and I will need to separate sequential and associative containers into different implementations. I really have tried a ton of combinations, including variadics and template template parameters. I can get many of them to work for multiple containers, but each has various issues as I think I'm getting to an answer. Conditional compilation like this (obviously with an enable/disable based on type_traits) seems like it might help with reaching a full solution in more than one of those cases.

Online version is here (just swap commenting of lines 47 & 48): http://coliru.stacked-crooked.com/a/d4892db81a4c9957

Any help appreciated.

rtillery
  • 367
  • 1
  • 10
  • 1
    While it's a valid question (why the last code snippet gives the error?), I think the actual problem is that you want to use `enable_if` in partial specialization. (in that case you need to put it in the `template<...>` part, see code in https://stackoverflow.com/questions/44585504/partial-template-function-specialization-with-enable-if-make-default-implementa for an example) – user202729 Feb 06 '21 at 05:08
  • I'm clearly new to `enable_if`, but from all of the many samples I've seen, it seems to go in the `template<>` declaration for templated functions, but in the `struct`/`class` definition for those: https://stackoverflow.com/a/42679086/3705286, https://stackoverflow.com/a/26447113/3705286, https://cpppatterns.com/patterns/class-template-sfinae.html, etc. Is this not correct? – rtillery Feb 06 '21 at 20:50

0 Answers0