Ich versuche, dieses Beispiel aus einem Plural Video zu verstehen (das ich ein wenig geändert haben):Decorator-Muster in C++ mit Vorlagen
#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;
}
Meine beiden wichtigsten Fragen, warum ist die partielle Spezialisierung und ist es möglich, den Code zu ändern, so dass es auch ein Lambda nehmen kann?
Sie werden zu 'std :: move' dass' Func' in den Speicher in Ihrem Make-Funktion wollen. Für industrielle Qualität würde ich auch einen konvertierenden ctor zu Logger schreiben (wo, wenn "FuncA" in "FuncB" umwandelbar ist, so ist "Logger' zu 'Logger '). Außerdem haben make und Logger ctor den String by-value und 'std :: move', um Zuweisungen zu sparen. –
Yakk
'decltype (auto) operator()' und 'declltype (auto) result' werden Unterstützung für die Rückgabe durch Referenz hinzufügen. – Potatoswatter
oh ich wusste nicht über auto/decltype (auto) diff, das ist ein gutes wissen :) –