微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

CRTP:即使使用静态多态,我也无法摆脱重复代码

如何解决CRTP:即使使用静态多态,我也无法摆脱重复代码

1.问题描述

我有两个类 Derived1Derived2。所有函数都是相同的,其中大部分包含大约 100 行。 唯一的区别是被操纵的静态对象。 Derived1 正在操纵 p1Derived2 正在操纵 p2。这两个类都使用静态函数。但是有一个约束,被操作的对象只能在包内部使用。文件结构如下:

/**
 * 
 * include/derived.hpp
 * include/derived1.hpp
 * include/derived2.hpp
 * 
 * src/point.hpp
 * src/derived.cpp
 * src/Derived1.cpp
 * src/derived2.cpp
 * 
 * Point is only visible in the package
 * */

2.问题

我不明白静态多态如何解决我的问题。我怎么能有一个 common 函数 create,它知道我像 p1p2 一样操作哪个静态实例,同时考虑到我之前陈述的约束:被操作的对象只能在包内使用。


3.源代码 c++ 11(我不能使用较新的版本)

代码基于以下文章Static Polymorphism in C++

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Point{
    std::vector<int> points;
};

static Point p1;
static Point p2;

template< class Derived >
class Base {
public:
    static void create() {
        Derived::create();
    }
    
    static void replace() {
        Derived::replace();
    }
    
    static void clear() {
        Derived::clear();
    }
};
 
class Derived1: public Base< Derived1 > {
    friend class Base< Derived1 >;
private:
    static void create() {
       p1.points = {1,2,3,4,5,6,7,8,9};
    }
    
    static void replace() {
       std::replace_if(p1.points.begin(),p1.points.end(),[](int x){return x > 4;},5);
       //100 more lines
    }
    
    static void clear() {
        p1.points.clear();
    }
};
 
class Derived2: public Base< Derived2 > {
    friend class Base< Derived2 >;
private:
   static void create() {
      p2.points = {1,9};
    }
    
    static void replace() {
        std::replace_if(p2.points.begin(),p2.points.end(),5);
        //100 more lines same as derived 1
    }
    
     static void clear() {
        p2.points.clear();
    }
};


int main()
{
    Base< Derived1 >::create();
    Base< Derived2 >::create();
    
    Base< Derived1 >::replace();
    Base< Derived2 >::replace();
    
    Base< Derived1 >::clear();
    Base< Derived2 >::clear();
    
    return 0;
}

解决方法

我不确定您是否可以将其与 CRTP 一起使用,但是使用非类型模板参数很容易:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct Point {
    std::vector<int> points;
};

// Hides the points
class Encapsulate {
    template<Point &p>
    class C {
      public:
        static void create() {
            p.points = {1,2,3,4,5,6,7,8,9};
        }

        static void replace() {
            std::replace_if(
                p.points.begin(),p.points.end(),[](int x) { return x > 4; },5);
            // 100 more lines same as derived 1
        }

        static void clear() {
            p.points.clear();
        }
    };
    static Point p1;
    static Point p2;

  public:
    using C1 = C<p1>;
    using C2 = C<p2>;
};

// Need to define them out-of-line or use C++17 inline keyword above
Point Encapsulate::p1;
Point Encapsulate::p2;

using C1 = Encapsulate::C1;
using C2 = Encapsulate::C2;

// You can still get to it,but that is basically always possible.
template<class T>
struct extract_point;

template<template<Point &> class T,Point &p>
struct extract_point<T<p>> {
    static Point &point;
};
template<template<Point &> class T,Point &p>
Point &extract_point<T<p>>::point = p;

int main() {
    C1::create();
    C2::create();

    C1::replace();
    C2::replace();

    C1::clear();
    C2::clear();

    auto &p1 = extract_point<C1>::point;

    return 0;
}

这适用于所有静态 Point(基本上,必须在编译时知道地址才能使其工作)。也没有间接的运行时开销,因为编译器知道 p 在编译时引用了什么。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。