C++:类型擦除

/ C++ / 没有评论 / 957浏览

记录一下模板类型擦除

#pragma once

#include <iostream>
using namespace std;

template<typename R, typename... Args>
class FunctorBridge {
public:

    virtual ~FunctorBridge() = default;

    virtual FunctorBridge* clone() const = 0;

    virtual R invoke(Args... args) = 0;

    virtual R invoke(Args... args) const = 0;
};


template<typename Functor, typename R, typename... Args>
class SpecificFunctorBridge : public FunctorBridge<R, Args...> {
    Functor functor;
public:
    template<typename FunctorFwd>
    explicit SpecificFunctorBridge(FunctorFwd&& functor)
        : functor(std::forward<FunctorFwd>(functor)) {}

    virtual SpecificFunctorBridge* clone() const override {
        return new SpecificFunctorBridge(functor);
    }

    virtual ~SpecificFunctorBridge() {
        std::cout << "~SpecificFunctorBridge" << std::endl;
    }

    R invoke(Args ... args)  override {
        return functor(std::forward<Args>(std::forward<Args>(args))...);
    }

    R invoke(Args ... args) const override {

        return functor(std::forward<Args>(std::forward<Args>(args))...);
    }
};


//声明
template<typename Signature>
class FunctionPtr;

//特化
template<typename R, typename ...Args>
class FunctionPtr<R(Args...)> {
private:
    FunctorBridge<R, Args...>* bridge;
public:
    FunctionPtr() : bridge(nullptr) {}

    ~FunctionPtr() {
        std::cout << "~FunctionPtr" << std::endl;
        if (bridge) {
            delete bridge;
            bridge = nullptr;
        }
    }

    template<typename F>
    FunctionPtr(F&& f) {
        using Functor = decay_t<F>;
        using Bridge = SpecificFunctorBridge<Functor, R, Args...>;
        bridge = new Bridge(forward<F>(f));
    }

    R operator()(Args...args) {
        return bridge->invoke(std::forward<Args>(args)...);
    }
};

class AA {
private:
    int xx;
public:
    void operator()(int x) {
        xx++;
        cout << "A::operator()()" << endl;
    }

    void operator()(int x) const {
        cout << "A::operator()() const" << endl;
    }

    ~AA() {
        std::cout << "~AA" << std::endl;
    }
};

void pr(int x) {
    cout << "pr" << endl;
}

int main()
{
    // lamda
    FunctionPtr<void(int)> xx([](int b) {
        cout << "hello world" << b << endl;
        });
    xx(12);

    //函数指针
    FunctionPtr<void(int)> xy(pr);
    xy(12);

    //函数对象
    //AA a{};
    FunctionPtr<void(int)> xz(AA{});
    xz(12);
    return 0;
}

----

//**https://zhuanlan.zhihu.com/p/351291649**

#pragma once
#include <iostream>

using namespace std;

struct task_base {
    virtual ~task_base() {}
    virtual void operator()() const = 0;
};


template <typename F>
struct task_model : public task_base
{
    F functor_;

    template <typename U> //构造函数是函数模板
    task_model(U&& f) : functor_(std::forward<U>(f)) {}

    void operator()() const override 
    {
        functor_();
    }
};

class my_task;

//C++20以下
//template <typename F>
//using is_not_my_task = std::enable_if_t<
//    !std::is_same_v< std::remove_cvref_t<F>, my_task >,
//    int>;
//
//template <
//    typename F,
//    is_not_my_task<F> = 0>
//my_task(F&& f);

template <typename F>
concept is_not_my_task = !std::is_same_v<std::remove_cvref_t<F>, my_task>;

class my_task {
    std::unique_ptr<task_base> ptr_;

public:

    template <typename F>
    requires is_not_my_task<F>
    my_task(F&& f)
    {
        using F_decay = std::decay_t<F>;   //类型退化,函数可以赋值成函数指针
        using model_type = task_model<F_decay>;
        ptr_ = std::make_unique<model_type>(std::forward<F_decay>(f));
    }

    void operator()() const 
    {
        ptr_->operator()();
    }

    // 其他部分略
     // 移动构造函数
    my_task(my_task&& oth) noexcept : ptr_(std::move(oth.ptr_))
    {}

    // 移动赋值函数
    my_task& operator=(my_task&& rhs) noexcept 
    {
        ptr_ = std::move(rhs.ptr_);
        return *this;
    }

    // 析构函数
    ~my_task() = default;

    // 删除复制构造函数、复制赋值函数
    my_task(const my_task&) = delete;
    my_task& operator=(const my_task&) = delete;
};

// 普通函数
void foo() 
{
    std::cout << "type erasure 1" << std::endl;
}

// 重载括号运算符的类
struct foo2 
{
    void operator()() const
    {
        std::cout << "type erasure 2" << std::endl;
    }
};

#include <fstream>
#include <string>

int main()
{
    task_model<decltype(&foo)> t7{ &foo };

    my_task t1{ &foo };
    t1(); // 输出"type erasure 1"

    my_task t4{ foo };
    t4();

    my_task t2{ foo2{} };
    t2(); // 输出"type erasure 2"

    // Lambda
    my_task t3{
        []() { std::cout << "type erasure 3" << std::endl; }
    };
    t3(); // 输出"type erasure 3"

    my_task t5{
        []() { std::cout << "type erasure"; }
    };

    //无法调用复制构造函数,这里会调用构造函数,加上限制,会禁止调用
    //my_task t6{ t5};
      return 0;
}