gpt4 book ai didi

c++ - C++ 中带有模板的装饰器模式

转载 作者:行者123 更新时间:2023-11-30 01:08:41 35 4
gpt4 key购买 nike

我试图从 pluralsight 视频中理解这个例子(我已经做了一些修改):

#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;
}

我的两个主要问题是为什么是偏特化,是否可以修改代码使其也可以采用 lambda?

最佳答案

why is the partial specialization?

目的是提供一个函数类型,同时也得到它的返回类型和参数类型。
您只能通过部分特化来做到这一点,即以下特化:

template<typename> struct S;

template<typename R, typename... Args>
struct S<R(Args...)> { /* ... */ };

如您所见,主模板没有定义,因为在这种情况下根本不需要它。
无论如何,请注意它只接受一种类型。目的是按如下方式使用它:S<void(int, char)> .
你怎么知道返回类型是 voidintchar您的参数在主模板中吗?你不能,但你可以在专业范围内做。

is it possible to modify the code so it can take a lambda as well?

你甚至可以去掉 std::function s 和函数指针,以便有一个仅基于 lambda 的解决方案。使用 lambda,您可以轻松捕获或调用其他函数。

这是一个最小的工作示例:

#include <iostream>
#include<type_traits>
#include <utility>

template <typename F>
struct Logger: F
{
std::string name_;

Logger(F &&func, const std::string& name):
F{std::move(func)}, name_{name} {}

template<typename... Args>
auto operator() (Args&&... args)
{
std::cout << "Entering " << name_ << std::endl;
auto result = F::operator()(std::forward<Args>(args)...);
std::cout << "Exiting " << name_ << std::endl;
return result;
}
};

template <typename F>
auto make_logger(F &&f, const std::string& name)
{
return Logger<std::decay_t<F>>{std::move(f), 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([](auto... args) { return add(args...); }, "Add");
auto result = logged_add(2,3,5);
}

关于c++ - C++ 中带有模板的装饰器模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41656705/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com