Consider this simple class derived from std::variant
:
#include <string>
#include <variant>
class my_variant : public std::variant<int, std::string>
{
using variant::variant;
public:
std::string foo()
{
return "foo";
}
};
Notice, I am deliberately adding using variant:variant
so that constructors from the base class are exposed in the derived class. If you do not do this, instances of my_variant
class will not work with operator=
without a bunch of re-definitions.
This compiles just fine.
Now let's start turning it into a template step-by-step.
template <typename TChr>
class my_variant : public std::variant<int, std::string>
{
using variant::variant;
public:
// Changed to templated return type, compiles fine
std::basic_string<TChr> foo()
{
return "foo";
}
};
Here, the only change is that we make use of the template parameter in the foo()
method. Everything still compiles fine.
And now this:
template <typename TChr>
class my_variant : // Changed to templated base class
public std::variant<int, std::basic_string<TChr>>
{
// Now this line won't compile !!
using variant::variant;
public:
std::basic_string<TChr> foo()
{
return "foo";
}
};
As soon as I make use of the template parameter to describe the base class, I am getting the following compiler error:
'variant': is not a class or namespace name
for this line: using variant::variant;
I do not fully understand why this specific change causes a problem. So far I was thinking in the direction that maybe using variant::variant
without specifying its template signature is a problem, so I tried this:
template <typename TChr>
class my_variant :
public std::variant<int, std::basic_string<TChr>>
{
// Added templating here, still fails with the same error message.
using variant<int, std::basic_string<TChr>>::variant;
public:
std::basic_string<TChr> foo()
{
return "";
}
};
Doing so generates the same error message, so I must be doing something wrong.
Compiler is MSVC 2022, C++20 mode.
[...] So I must be doing something wrong!!
Since in the last my_variant
, the parent std::variant
depends upon the class template argument, you also need the constructor from the correct parent
template <typename TChr>
class my_variant : public std::variant<int, std::basic_string<TChr>>
{
using std::variant<int, std::basic_string<TChr>>::variant;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
public:
std::basic_string<TChr> foo()
{
return "foo";
}
};
That has been mentioned, also have a read here, for more about your approach:
Is it okay to inherit implementation from STL containers, rather than delegate?