samedi 14 janvier 2017

Decorator Pattern in C++ with templates

I am trying to understand this example from a pluralsight video (that I've modified a little):

#include <iostream>
#include <functional>

//this next line is partial specialization, but I don't understand why it's necessary
template<typename> struct Logger;

template <typename R, typename... Args>
struct Logger<R(Args...)>
{
    std::function<R(Args...)> func_;
    std::string name_;

    Logger(const std::function<R(Args...)>& func, const std::string& name):
        func_{func}, name_{name} {}

    R operator() (Args... args)
    {
        std::cout << "Entering " << name_ << std::endl;
        R result = func_(args...);
        std::cout << "Exiting " << name_ << std::endl;
        return result;
    }
};

// this is how the example was originally written.  It uses a function pointer as an argument which is ok except you can't give it a lambda.  
template <typename R, typename... Args>
auto make_logger(R (*func)(Args...), const std::string& name) ->Logger<R(Args...)>
{
    return Logger<R(Args...)>{std::function<R(Args...)>(func), name};
}

//this is my attempt to make it so it will accept a lambda but it doesn't work.
template <typename R, typename... Args>
auto make_logger2(std::function<R(Args...)> func, const std::string& name) ->Logger<R(Args...)>
{
    return Logger<R(Args...)>{std::function<R(Args...)>(func), name};
}

double add(double a, double b, double c)
{
    std::cout << a  << " + " << b << " + " << c << " = " << a + b + c << std::endl;

    return a + b + c;
}

int main()
{

    auto logged_add = make_logger(add,"Add");
    auto result = logged_add(2,3,5);

//    auto lm  = [](std::string str1, std::string str2){return str1 + str2;};
//    auto logged_string = make_logger2(lm, "string add");
//    auto result2 = logged_string("Hello ", "World!");

    //I get the following compile error if the next two lines are uncommented:
    // main.cpp:101: error: no matching function for call to 'make_logger2(main()::<lambda(std::__cxx11::string, std::__cxx11::string)>, const char [11])'

    //auto logged_string = make_logger2([](std::string str1, std::string str2){return str1 + str2;},"string add");
    //auto result2 = logged_string("Hello ", "World!");

    std::cout << "result = " << result << std::endl;
    //std::cout << "result2 = " << result2 << std::endl;

    return 0;
}

My main two questions are why is the partial specialization and is it possible to modify the code so it can take a lambda as well?

Aucun commentaire:

Enregistrer un commentaire