trouble exposing inherited constructors when using nested templating

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?

Leave a Reply