使用嵌套模板时如何公开继承的构造函数?

Reg*_*gus 3 c++ inheritance templates class-template c++20

考虑这个简单的类派生自std::variant

#include <string>
#include <variant>

class my_variant : public std::variant<int, std::string>
{
    using variant::variant;
public:
    std::string foo()
    {
        return "foo";
    }
};
Run Code Online (Sandbox Code Playgroud)

请注意,我故意添加using variant:variant以便在派生类中公开基类的构造函数。如果不这样做,类的实例将无法 在没有大量重新定义的情况下my_variant工作。operator=这编译得很好。


现在让我们开始逐步将其变成模板。

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";
    }
};
Run Code Online (Sandbox Code Playgroud)

在这里,唯一的变化是我们在方法中使用了模板参数foo()。一切仍然编译良好。

现在这个:

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";
    }
};
Run Code Online (Sandbox Code Playgroud)

一旦我使用模板参数来描述基类,我就会收到以下编译器错误:

'variant': is not a class or namespace name 
Run Code Online (Sandbox Code Playgroud)

对于这一行:using variant::variant;

我不完全理解为什么这个特定的变化会导致问题。到目前为止,我在想,也许using variant::variant不指定其模板签名是一个问题,所以我尝试了这个:

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 "";
    }
};
Run Code Online (Sandbox Code Playgroud)

这样做会产生相同的错误消息,所以我一定做错了什么。

编译器是MSVC 2022,C++20模式。

JeJ*_*eJo 5

[...]所以我一定做错了什么!

由于在最后一个中 my_variant,父级std::variant依赖于类模板参数,因此您还需要来自正确父级的构造函数


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";
    }
};
Run Code Online (Sandbox Code Playgroud)

已经提到过,也请阅读此处,了解有关您的方法的更多信息:

可以从 STL 容器继承实现而不是委托吗?

  • 谢谢,在variant::variant前面指定std命名空间确实消除了这个问题。奇怪的是,如果我对第一个和第二个示例(那些编译良好的示例)执行相同的操作,它们现在将无法编译。是的,谢谢您的链接。 (2认同)