2

This is just short inquiry if it is at all possible to somehow import base class constructors without all the template bloat. Consider this example where I'm inheriting from a templated 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;
};

You can see that there's quite a bit of bloat which makes it rather unreadable and error prone. Can this be avoided? The reason I'm asking is because I think I once heard that you can somehow skip template parameters within a templated class as the compiler can imply what you meant.

Clarification

Essentially I'm just looking for a way to not writing the same template mess twice. I have tried using variant::variant which doesn't work. But there might be other ways around this and any hints are greatly appreciated!

4
  • Well? Did you try to determine if the rumors you heard are true? It should take no more than a second, or two and then you can go from there? Commented Apr 14, 2023 at 12:19
  • @SamVarshavchik It doesn't work with just using variant::variant as I have tried that. But this can't be the bottom of it x_X Commented Apr 14, 2023 at 12:25
  • 2
    Add an alias? using base_t = your_big_type; using base_t::base_t; Commented Apr 14, 2023 at 12:25
  • @NathanOliver Yes but then I have to template the type alias and essentially I still have to write it twice so I wouldn't exactly call that a "solution". EDIT: I know what you mean: I would only have to use two template parameters. That is better yes Commented Apr 14, 2023 at 12:29

3 Answers 3

7

The injected class name from the base class won't be found by unqualified lookup because the base class is a template that depends on template parameters of the derived class. Let's qualify that name:

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;
};

Demo

Sign up to request clarification or add additional context in comments.

4 Comments

@OP I'd recommend accepting this answer rather than mine, unless this is a pattern you're using all over the place
This! I was looking for this. Then you might as well do just using JSON::variant::variant right?
@glades MSVC doesn't accept using JSON::variant::variant;. My own preference would be to add an alias for clarity anyway.
Finally a sane solution! Although the question is a duplicate. I won't vote to close, because of this excellent answer.
3

You could write an alias template to factor out some of the repetition:

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;
};

Comments

0

Quick idea: use inheritance to inherit that name

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;
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.