与AI合作 -- 写一个modern c++单例工厂

发布时间:2024年01月08日

目录

前言

提问

bard给出的答案

AI答案的问题

要求bard改进

?人类智能

AI VS 人类


前言

通过本文读者可以学到modern C++单例模式+工厂模式的混合体,同时也能看到:如今AI发展到了怎样的智能程度?怎样让AI帮助我们快速完成实现头脑中的想法?以及这样的智能程度会不会让程序员失业?

提问

这次我不用ChatGPT了,而是换成了bard.

mzhai:?Write a Modern c++ program to implement a singleton factory to produce 2 products. Each product has different arguments, the 1st has only one parameter of type int, the 2nd product has two parameters int and string respectively.

?这里我特意提出要创建两个参数不同的产品,防止AI写出来的类不通用(有点像避免算法过拟合的感觉)。

bard给出的答案

  1 #include <iostream>
  2 #include <memory>
  3 #include <utility>
  4
  5 enum class ProductType {
  6     Product1,
  7     Product2
  8 };
  9
 10 class Product {
 11 public:
 12     virtual ~Product() = default;
 13     virtual void use() = 0;
 14 };
 15
 16 // Concrete products with different arguments
 17 class Product1 : public Product {
 18 public:
 19     Product1(int arg1) : arg1_(arg1) {}
 20     void use() override { std::cout << "Using Product1 with arg1: " << arg1_ << std::endl; }
 21 private:
 22     int arg1_;
 23 };
 24
 25 class Product2 : public Product {
 26 public:
 27     Product2(int arg2_1, std::string arg2_2) : arg2_1_(arg2_1), arg2_2_(arg2_2) {}
 28     void use() override { std::cout << "Using Product2 with arg2_1: " << arg2_1_ << ", arg2_2: " << arg2_2_ << std::endl;     }
 29 private:
 30     int arg2_1_;
 31     std::string arg2_2_;
 32 };
 33
 34 // Singleton factory with modern techniques
 35 class ProductFactory {
 36 public:
 37     static ProductFactory& getInstance() {
 38         static ProductFactory instance;
 39         return instance;
 40     }
 41
 42     template <typename... Args>
 43     std::unique_ptr<Product> createProduct(ProductType type, Args&&... args) {
 44         switch (type) {
 45             case ProductType::Product1:
 46                 return std::make_unique<Product1>(std::forward<Args>(args)...);
 47             case ProductType::Product2:
 48                 return std::make_unique<Product2>(std::forward<Args>(args)...);
 49             default:
 50                 throw std::invalid_argument("Invalid product type");
 51         }
 52     }
 53
 54 private:
 55     ProductFactory() = default; // Private constructor for singleton
 56 };
 57
 58 int main() {
 59     ProductFactory& factory = ProductFactory::getInstance();
 60
 61     std::unique_ptr<Product> product1 = factory.createProduct(ProductType::Product1, 42);
 62     std::unique_ptr<Product> product2 = factory.createProduct(ProductType::Product2, 5, "Hello");
 63
 64     product1->use();
 65     product2->use();
 66
 67     return 0;
 68 }

AI答案的问题

第一次给出的答案编译失败,报错信息如下

/usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../include/c++/12/bits/unique_ptr.h:1065:34: error: no matching constructor for initialization of 'Product2'
?1065 | ? ? { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^ ? ~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/insights/insights.cpp:48:29: note: in instantiation of function template specialization 'std::make_unique<Product2, int>' requested here
? ?48 | ? ? ? ? ? ? ? ? return std::make_unique<Product2>(std::forward<Args>(args)...);
? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? ^

有点奇怪吧,62行我们明明给Product2传的是两个参数,不是有Product2才走case ProductType::Product2吗(48行)?但编译器却抱怨给Product2的构造函数只传了一个int。这是为什么哪?

这是因为case是运行时代码,而createProduct根据61、62行会产生两个重载,每个都包含全部代码。比如61行会产生如下code:

std::unique_ptr<Product> createProduct(ProductType type, int arg) {
    switch (type) {
        case ProductType::Product1:
            return std::make_unique<Product1>(arg);
        case ProductType::Product2:
            return std::make_unique<Product2>(arg);
        default:
            throw std::invalid_argument("Invalid product type");
    }
}

因为Product2的构造函数有两个参数,而此处只有一个(int arg), 故找不到匹配的构造函数。

要求bard改进

直接把错误贴给他,它还是没能正真理解编译失败的原因,之所以这么说,是因为它给出的解决方案是:

case ProductType::Product2:
                if constexpr (sizeof...(Args) == 2) { // Ensure 2 arguments for Product2
                    return std::make_unique<Product2>(std::forward<Args>(args)...);
                } else {
                    throw std::invalid_argument("Invalid arguments for Product2");
                }

?constexpr (sizeof...(Args) == 2) 确实在预处理阶段:如果条件不符合,这段代码就不要了,从而导致61行实例出来的createProduct函数不报错,但62行依然会报错。我们暂且按照这种思路试一试, 虽然它有问题(后面会说)。

  1 #include <iostream>
  2 #include <memory>
  3 #include <utility>
  4
  5 class Product {
  6 public:
  7     virtual ~Product() = default;
  8     virtual void use() = 0;
  9 };
 10
 11 // Concrete products with different arguments
 12 class Product1 : public Product {
 13 public:
 14     Product1(int arg1) : arg1_(arg1) {}
 15     void use() override { std::cout << "Using Product1 with arg1: " << arg1_ << std::endl; }
 16 private:
 17     int arg1_;
 18 };
 19
 20 class Product2 : public Product {
 21 public:
 22     Product2(int arg2_1, std::string arg2_2) : arg2_1_(arg2_1), arg2_2_(arg2_2) {}
 23     void use() override { std::cout << "Using Product2 with arg2_1: " << arg2_1_ << ", arg2_2: " << arg2_2_ << std::endl;     }
 24 private:
 25     int arg2_1_;
 26     std::string arg2_2_;
 27 };
 28
 29 class ProductFactory {
 30 public:
 31     static ProductFactory& getInstance() {
 32         static ProductFactory instance;
 33         return instance;
 34     }
 35     template <typename... Args>
 36     std::unique_ptr<Product> createProduct(Args&&... args) {
 37         if constexpr (sizeof...(Args) == 1){
 38             return std::make_unique<Product1>(std::forward<Args>(args)...);
 39         }
 40         if constexpr (sizeof...(Args) == 2){
 41             return std::make_unique<Product2>(std::forward<Args>(args)...);
 42         }
 43     }
 44 private:
 45     ProductFactory() = default; // Private constructor for singleton
 46 };
 47
 48 int main() {
 49     ProductFactory& factory = ProductFactory::getInstance();
 50
 51     std::unique_ptr<Product> product1 = factory.createProduct(42);
 52     std::string hi("Hello");
 53     std::unique_ptr<Product> product2 = factory.createProduct(5, hi);
 54
 55     product1->use();
 56     product2->use();
 57
 58     return 0;
 59 }

编译成功,运行也没问题。我们还可以通过cppinsights.io看看模板函数实例化出来的2个重载结果:

?显然这种办法不好:

  1. 请想一想如果product1 和Product2都只有一个参数哪?就无法通过sizeof区分了。
  2. 而且,这么做产生了很多无用代码(if constexpr...)

人类智能

所以还是由我给它快速改一改吧。我们直接给createProduct函数多传一个模板参数进去,比如叫T,像下面这样:

template <typename T, typename... Args>
std::unique_ptr<T> createProduct(Args&&... args) {
    return std::make_unique<T>(std::forward<Args>(args)...);
}

...

std::unique_ptr<Product> product1 = factory.createProduct<Product1>(42);
std::string hi("Hello");
std::unique_ptr<Product> product2 = factory.createProduct<Product2>(5, hi);

看下createProduct如何实例化的?

?问一下bard这么改怎么样?回答的井井有条!

mzhai:How about changing the code to above?

Bard: I'm happy to review the proposed code changes:

Key Changes:

  • Templated?createProduct?function:?The?createProduct?function now takes a template parameter?T?to specify the product type,?eliminating the need for the?ProductType?enum. (传了T就没必要传ProductType enum了)
  • Removal of?switch?statement:?The?switch?statement is no longer needed as the compiler determines the correct type based on the template argument.(createProduct中的Switch可以去掉了)
  • Explicit product type in?main:?The?createProduct?function is called with explicit template arguments (Product1?and?Product2) to create the desired product types.(main中要显示指定产品类型,即尖括号中的Product1、Product2)

Analysis:

  • Pros:
    • More concise and less verbose code. (代码简明)
    • Leverages template metaprogramming for type-driven behavior.(利用了模板元编程)
    • Potentially easier to extend for new product types.(新产品类型扩展更容易)
  • Cons:
    • Might be less readable for those less familiar with templates.(对不熟悉模板的人来说可读性变差)
    • Error messages might be more cryptic due to template instantiation.(因为模板实例导致报错信息比较神秘不那么直接,确实!)
    • Doesn't enforce a closed set of product types (could potentially create other types).(没有强制指定哪些产品类型能生产,有产生别的类型的风险)

Overall:

  • The changes are valid and adhere to modern C++ practices.
  • The choice between this approach and the previous one using the?ProductType?enum is mainly a matter of preference and trade-offs.
  • Consider the team's familiarity with templates and the specific project requirements when deciding on the best approach.

Additional Notes:

  • Ensure that all product classes (Product1,?Product2,?etc.) are derived from the?Product?base class for this approach to work correctly.
  • Consider using?static_assert?or concepts (if available in your C++ version) to enforce constraints on the template parameter?T,?ensuring it's a valid product type.

AI VS 人类

AI确实智商还有限,但也确实能提高编程效率,copilot等等一般宣传能提高人类编程效率50%左右,在没有增量就业机会的情况下也就是一半工程师要失业了???

附上最终代码

便于大家COPY及实验。

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

class Product {
public:
    virtual ~Product() = default;
    virtual void use() = 0;
};

// Concrete products with different arguments
class Product1 : public Product {
public:
    Product1(int arg1) : arg1_(arg1) {}
    void use() override { std::cout << "Using Product1 with arg1: " << arg1_ << std::endl; }
private:
    int arg1_;
};

class Product2 : public Product {
public:
    Product2(int arg2_1, std::string arg2_2) : arg2_1_(arg2_1), arg2_2_(arg2_2) {}
    void use() override { std::cout << "Using Product2 with arg2_1: " << arg2_1_ << ", arg2_2: " << arg2_2_ << std::endl; }
private:
    int arg2_1_;
    std::string arg2_2_;
};

class ProductFactory {
public:
    static ProductFactory& getInstance() {
        static ProductFactory instance;
        return instance;
    }

    template <typename T, typename... Args>
    //typename std::enable_if<std::is_same<Product,T>::value, void>::type
    std::unique_ptr<T> createProduct(Args&&... args) {
        return std::make_unique<T>(std::forward<Args>(args)...);
    }

private:
    ProductFactory() = default; // Private constructor for singleton
};

int main() {
    ProductFactory factory;

    std::unique_ptr<Product> product1 = factory.createProduct<Product1>(42);
    std::string hi("Hello");
    std::unique_ptr<Product> product2 = factory.createProduct<Product2>(5, hi);

    product1->use();
    product2->use();

    return 0;
}

文章来源:https://blog.csdn.net/zhaiminlove/article/details/135446120
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。