在导入大量模板化基类的基类构造函数时避免模板混乱

Avoid template mess when importing base class constructors of heavily templated base class

提问人:glades 提问时间:4/14/2023 最后编辑:Evgglades 更新时间:4/14/2023 访问量:83

问:

这只是一个简短的询问,如果有可能以某种方式导入基类构造函数,而没有所有的模板膨胀。考虑这个例子,我从模板化继承:std::variant

template <typename StringType, typename Allocator>
class JSON : public std::variant<std::monostate,
                        std::unordered_map<StringType, JSON<StringType, Allocator>, std::hash<JSON<StringType, Allocator>>, std::equal_to<StringType>, Allocator>,
                        std::vector<JSON<StringType, Allocator>, Allocator>, 
                        bool,
                        double,
                        StringType>
{
public:

    using std::variant<std::monostate,
                        std::unordered_map<StringType, JSON<StringType, Allocator>, std::hash<JSON<StringType, Allocator>>, std::equal_to<StringType>, Allocator>,
                        std::vector<JSON<StringType, Allocator>, Allocator>, 
                        bool,
                        double,
                        StringType>::variant;
};

你可以看到有相当多的臃肿,这使得它相当不可读且容易出错。这是可以避免的吗?我之所以这么问,是因为我想我曾经听说过,你可以以某种方式跳过模板化类中的模板参数,因为编译器可以暗示你的意思。

澄清:

从本质上讲,我只是在寻找一种方法来避免将相同的模板写成两团糟。我试过了,但不起作用。但是可能还有其他方法可以解决这个问题,任何提示都非常感谢!using variant::variant

C++ 模板 构造函数 基类 using-directives

评论

0赞 Sam Varshavchik 4/14/2023
井?你有没有试图确定你听到的谣言是否属实?它应该不超过一两秒钟,然后你就可以从那里开始了?
0赞 glades 4/14/2023
@SamVarshavchik 正如我尝试过的那样,仅使用 variant::variant 是行不通的。但这不可能是它的底部x_X
2赞 NathanOliver 4/14/2023
添加别名?using base_t = your_big_type; using base_t::base_t;
0赞 glades 4/14/2023
@NathanOliver 是的,但是我必须对类型别名进行模板化,基本上我仍然需要编写两次,所以我不会完全称其为“解决方案”。编辑:我知道你的意思:我只需要使用两个模板参数。那更好,是的

答:

3赞 TartanLlama 4/14/2023 #1

您可以编写一个别名模板来消除一些重复:

template <template <class...> class Temp, class StringType, class Allocator>
using variant_for = std::variant<std::monostate,
                        std::unordered_map<StringType, Temp<StringType, Allocator>, std::hash<Temp<StringType, Allocator>>, std::equal_to<StringType>, Allocator>,
                        std::vector<Temp<StringType, Allocator>, Allocator>, 
                        bool,
                        double,
                        StringType>;

template <typename StringType, typename Allocator>
class JSON : public variant_for<JSON, StringType, Allocator>
{
public:
    using variant_for<JSON, StringType, Allocator>::variant;
};
0赞 MSalters 4/14/2023 #2

快速构思:使用继承来继承该名称

template <typename StringType, typename Allocator>
class JSONbase
{
public:
    using JSONStr = JSON<StringType, Allocator>;
    using variant = std::variant<std::monostate,
                        std::unordered_map<StringType, JSONStr, std::hash<JSONStr>, std::equal_to<StringType>, Allocator>,
                        std::vector<JSONStr, Allocator>, 
                        bool,
                        double,
                        StringType>::variant;
}

template <typename StringType, typename Allocator>
class JSON : 
    public JSONbase<StringType, Allocator>,
    public typename JSONbase<StringType, Allocator>::variant
{
   using variant::variant;
};
7赞 Evg 4/14/2023 #3

非限定查找不会找到基类中注入的类名,因为基类是依赖于派生的模板参数的模板。让我们限定该名称:

template <typename StringType, typename Allocator>
class JSON : public std::variant<std::monostate,
                        std::unordered_map<StringType, JSON<StringType, Allocator>, std::hash<JSON<StringType, Allocator>>, std::equal_to<StringType>, Allocator>,
                        std::vector<JSON<StringType, Allocator>, Allocator>, 
                        bool,
                        double,
                        StringType>
{
private:
    using MyBase = typename JSON::variant;

public:
    using MyBase::MyBase;
};

演示

评论

0赞 TartanLlama 4/14/2023
@OP我建议接受这个答案而不是我的答案,除非这是你到处使用的模式
0赞 glades 4/14/2023
这!我一直在寻找这个。那你还不如做恰到好处呢?using JSON::variant::variant
1赞 Evg 4/14/2023
@glades MSVC 不接受 .为了清楚起见,我自己的偏好是添加一个别名。using JSON::variant::variant;
0赞 Red.Wave 4/15/2023
终于一个理智的解决方案了!虽然这个问题是重复的。我不会投票结束,因为这个很好的答案。