vendredi 26 juin 2015

Specializations for different types

Can someone tell me how to remove the repeated specializations below?

#include <iostream>
#include <fstream>
#include <string>

struct Thing {
    int a, b;
    void load (std::istream& is) {is >> std::skipws >> a >> b;}
};

struct Object {
    int a, b, c;
    void load (std::istream& is) {is >> std::skipws >> a >> b >> c;}
};

template <typename...> struct PassArgs;

// General case.
template <typename First, typename... Rest>
struct PassArgs<First, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, First& first, Rest&... rest) const {
        is >> first;
        PassArgs<Rest...>::operator()(is, rest...);
    }
};

// Specialization for std::string needed.
template <typename... Rest>
struct PassArgs<std::string, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, std::string& first, Rest&... rest) const {
        while (std::getline (is, first) && first.empty());
        PassArgs<Rest...>::operator()(is, rest...);
    }
};

// Specialization for class Thing.
template <typename... Rest>
struct PassArgs<Thing, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, Thing& first, Rest&... rest) const {
        first.load(is);
        PassArgs<Rest...>::operator()(is, rest...);
    }
};

// Specialization for class Object, but is the exact same as that for Thing.
template <typename... Rest>
struct PassArgs<Object, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, Object& first, Rest&... rest) const {
        first.load(is);
        PassArgs<Rest...>::operator()(is, rest...);
    }
};


template <>
struct PassArgs<> {
    void operator()(std::istream&) const {}  // End of recursion.
};


int main() {}

Everything works correctly, but is there a way to avoid specializations for all classes that have the load(std::istream&) function (and there are many in my program). Currently, I have specializations for Thing, Object, and many other classes which all have the same lines in their specializations.

Incidentally, this is how the client uses PassArgs:

template <typename T, typename... Args>
T* create (std::istream& is, Args&... args) {
    PassArgs<Args...>()(is, args...);
    T* t = new T(args...);
    // Do whatever with t;
    return t;
}

Aucun commentaire:

Enregistrer un commentaire