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 derived class. If you don’t 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:
std::basic_string<TChr> foo() //Changed to templated return type, compiles fine
{
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 : public std::variant<int, std::basic_string<TChr>> //Changed to templated base class
{
using variant::variant; //Now this line won't compile
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>>
{
using variant<int, std::basic_string<TChr>>::variant; //Added templating here, still fails with the same error message
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.
>Solution :
[…] 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?