Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ wrapper around any collection type using templates

Extremely new to c++ however have a question regarding templates

Suppose I have a simple template class as defined below:

template<typename Collection>
class MySack {
private:
    Collection c;

public:
    typedef typename Collection::value_type value_type;

    void add(const value_type& value) {
        c.push_back(value);
    }
};

The aim of the class being to accept any type of collection, and allow a user to insert the correct type of value for the specified typename Collection.

The obvious problem is that this is only going to work for types which have a push_back method defined, which means it would work with list however not with set.

I started reading about template specialization to see if that'd be any help, however I don't think this would provide a solution as the type contained within the set would have to be known.

How would this problem be approached in c++?

like image 404
Eladian Avatar asked Apr 20 '18 06:04

Eladian


People also ask

What is the use of wrapper in C++?

The wrapper is C++ but exposes itself as C. Meaning the exposed C functions are C functions. However, this needs to be compiled as C++ in order to use new and delete for proper C++ class initialization. The wrapper creates a struct and puts the CPPMather object into it as as void pointer. This struct allows us to use it in a type safe manner in C.

How to wrap a C++ object in C?

Wrapping C++ objects in C 1 Introduction. Using C functions from C++ is very easy but going the other way isn’t. ... 2 The C++ Object We Want to Wrap 3 The Wrapper. The wrapper is C++ but exposes itself as C. ... 4 Example application. The C file (main.c) will use the C functions exposed by the wrapper’s header file. 5 Build and Running. ...

What do you need to know about wrapper class?

Our wrapper class has to: The first thing that our wrapper needs to provide are uniform interfaces, in our case, it is int (*behavior) (). Our wrapper class has to manage the lifetime of the objects to avoid using dangling references or pointers.

What are templates in C++ and how to use them?

In C++ you can achieve this with Templates. Using templates we can ask the compiler to generate functions/classes for us based on the types used in our code. This helps us to not write similar blocks of code multiple times to keep our code neat. Here’s a simple example:


2 Answers

You can use std::experimental::is_detected and if constexpr to make it work:

template<class C, class V>
using has_push_back_impl = decltype(std::declval<C>().push_back(std::declval<V>()));

template<class C, class V>
constexpr bool has_push_back = std::experimental::is_detected_v<has_push_back_impl, C, V>;

template<typename Collection>
class MySack {
private:
    Collection c;

public:
    typedef typename Collection::value_type value_type;

    void add(const value_type& value) {
        if constexpr (has_push_back<Collection, value_type>) {
            std::cout << "push_back.\n";
            c.push_back(value);
        } else {
            std::cout << "insert.\n";
            c.insert(value);
        }
    }
};

int main() {
    MySack<std::set<int>> f;
    f.add(23);

    MySack<std::vector<int>> g;
    g.add(23);
}
like image 87
llllllllll Avatar answered Nov 03 '22 02:11

llllllllll


You can switch to insert member function, which has the same syntax for std::vector, std::set, std::list, and other containers:

void add(const value_type& value) {
   c.insert(c.end(), value);
}

In C++11, you might also want to create a version for rvalue arguments:

void add(value_type&& value) {
   c.insert(c.end(), std::move(value));
}

And, kind-of simulate emplace semantics (not truly in fact):

template <typename... Ts>
void emplace(Ts&&... vs) {
   c.insert(c.end(), value_type(std::forward<Ts>(vs)...));
}

...

int main() {
   using value_type = std::pair<int, std::string>;

   MySack<std::vector<value_type>> v;
   v.emplace(1, "first");

   MySack<std::set<value_type>> s;
   s.emplace(2, "second");

   MySack<std::list<value_type>> l;
   l.emplace(3, "third");
}
like image 45
Daniel Langr Avatar answered Nov 03 '22 01:11

Daniel Langr