Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading