Skip to content

Latest commit

 

History

History
169 lines (133 loc) · 4 KB

cpp_forwarding.rst

File metadata and controls

169 lines (133 loc) · 4 KB

Perfect Forwarding

Perfect forwarding is a way for a programmer to design a generic wrapper function in their C++ programs. However, few examples show how to use it in a real scenario. Instead of explaining what a C++ perfect forwarding is, this article tries to collect use cases about using it.

Decorator Pattern

#include <iostream>
#include <utility>
#include <chrono>

template <typename Func, typename ...Args>
auto Decorator(Func &&f, Args&&... args) {

    const auto s = std::chrono::system_clock::now();
    auto ret = f(std::forward<Args>(args)...);
    const auto e = std::chrono::system_clock::now();
    std::chrono::duration<double> d = e - s;

    std::cout << "Time Cost: " << d.count() << std::endl;
    return ret;
}

long fib(long n) {
    return n < 2 ? 1 : fib(n-1) + fib(n-2);
}

int main() {
    Decorator(fib, 35);
    return 0;
}

Profiling

#include <iostream>
#include <utility>
#include <chrono>

class Timer {
public:
    Timer() : s_(std::chrono::system_clock::now()) {}
    ~Timer() {
        e_ = std::chrono::system_clock::now();
        std::chrono::duration<double> d = e_ - s_;
        std::cout << "Time Cost: " << d.count() << std::endl;
    }
private:
    std::chrono::time_point<std::chrono::system_clock> s_;
    std::chrono::time_point<std::chrono::system_clock> e_;
};

template <typename Func, typename ...Args>
auto Profile(Func f, Args&&... args) {
    Timer timer;
    return f(std::forward<Args>(args)...);
}

long fib1(long n) {
    return (n < 2) ? 1 : fib1(n-1) + fib1(n-2);
}

template<long N>
struct f {
    static constexpr long v = f<N-1>::v + f<N-2>::v;
};

template<>
struct f<0> {
    static constexpr long v = 0;
};

template<>
struct f<1> {
    static constexpr long v = 1;
};

int main() {
    long ret = -1;
    ret = Profile(fib1, 35);
    std::cout << ret << std::endl;

    ret = Profile([](){ return f<35>::v; });
    std::cout << ret << std::endl;
    return 0;
}

Factory Pattern

#include <iostream>
#include <utility>
#include <string>
#include <memory>

struct PostgresqlConfig { /* implementation */ };
struct MysqlConfig { /* implementation */ };

template <typename DB>
class Session {
public:
    void connect(const std::string url) {
        static_cast<DB*>(this)->connect(url);
    }
};

class Postgresql : public Session<Postgresql> {
private:
    PostgresqlConfig config_;
public:
    Postgresql(PostgresqlConfig c) : config_(c) {}

    void connect(const std::string url) {
        std::cout << "Connecting to Postgresql..." << std::endl;
        // connecting
    }
};

class Mysql : public Session<Mysql> {
private:
    MysqlConfig config_;
public:
    Mysql(MysqlConfig c) : config_(c) {}

    void connect(const std::string url) {
        std::cout << "Connecting to Mysql..." << std::endl;
        // connecting
    }
};

/**
 * An example of Perfect Forwarding
 */
template <typename S, typename C>
std::shared_ptr<S> SessionFactory(C&& c) {
    return std::make_shared<S>(std::forward<C>(c));
}

using PostgresSession = Session<Postgresql>;
using MysqlSession = Session<Mysql>;
using PostgresPtr = std::shared_ptr<PostgresSession>;
using MysqlPtr = std::shared_ptr<MysqlSession>;

int main(int argc, char *argv[]) {

    PostgresqlConfig pc;
    MysqlConfig mc;

    PostgresPtr ps = SessionFactory<Postgresql>(pc);
    MysqlPtr ms = SessionFactory<Mysql>(mc);

    ps->connect("postgresql://...");
    ms->connect("mysql://...");
    return 0;
}