Background & Goal
I wanted to create some sort of data utility, that stores an std::stringstream, as well as the format, the content is currently in. This shall give you type safety and IntelliSense as to that content representation your data currently has. Basically, it creates or removes a template parameter for every operation (compression, encoding, parsing, etc.):
// content representations/states
enum class ContentTypes
{
binary = 1,
text = 2,
json = 3,
zlib = 4
};
template <ContentTypes... PreviousTypes>
class X
{
public:
X<ContentTypes::zlib, PreviousTypes...> zlib()
{
return X<ContentTypes::zlib, PreviousTypes...>();
}
};
template <ContentTypes... PreviousTypes>
class X<ContentTypes::zlib, PreviousTypes...> : public X<(ContentTypes::zlib, PreviousTypes)...>
{
public:
X<PreviousTypes...> decompress()
{
return X<PreviousTypes...>();
}
};
#include <string>
#include <iostream>
int main()
{
/// deterministic and compile-time safety as to what content type the data has
X<ContentTypes::binary> foo; // some binary data (X<ContentTypes::binary>)
auto compressed = foo.zlib(); // X<ContentTypes::zlib, ContentTypes::binary>
auto compressed2 = compressed.zlib(); // X<ContentTypes::zlib, ContentTypes::zlib, ContentTypes::binary>
auto decompressed = compressed2.decompress(); // X<ContentTypes::zlib, ContentTypes::binary>
auto decompressed2 = decompressed.decompress(); // X<ContentTypes::binary>
return 0;
}
Problem
as you may have noticed, there is a mistake in the template specialization:
class X<ContentTypes::zlib, PreviousTypes...> : public X<(ContentTypes::zlib, PreviousTypes)...>
which results in wrong content types. If you try to compile the above code, you will get an error that the variable decompressed (which is actually of type X<ContentTypes::binary>, instead of X<ContentTypes::zlib, ContentTypes::binary>) has no attribute decompress. That is correct, since X<ContentTypes::binary> has no function called decompress. I don't know how to "inherit" the methods of the upper template instantiation to the specialization in the lower one without ending up with a recursive template.
The resulting GCC error:
.../src/main.cpp:52:39: error: 'class X<ContentTypes::binary>' has no member named 'decompress'
52 | auto decompressed2 = decompressed.decompress(); // X<ContentTypes::binary>
| ^~~~~~~~~~
Attempts so far
- I've searched some literature on C++ template specialization and parameter pack expansion, but to no success
- ChatGPT was great for discovering new ways to break my code and offered the
(ContentTypes::zlib, PreviousTypes)...expansion, which I think isn't correct at all because it just performs comma operator...
If you need more information, just ask in a comment. Thanks in advance! :)
Thanks for the helpful comments! I received a hint that brought me to a working solution:
Full code
Explaination
The inheritance done in a proper way would create a recursive template, which aborts compilation, since the name of the derived and parent class are identical (
X). Just by renaming the parent class toXbaseand inheriting from that, this problem is solved. Now you just need to create a new base template classXthat also inherits fromXBaseto make things complete.