RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 630268
Accepted
αλεχολυτ
αλεχολυτ
Asked:2020-02-20 18:31:28 +0000 UTC2020-02-20 18:31:28 +0000 UTC 2020-02-20 18:31:28 +0000 UTC

消除具有不同常量的函数中的代码重复

  • 772

考虑这段代码:

struct B {};
struct D1 : B {};
struct D2 : B {};

#define get if (s) return d1; else return d2;

volatile bool s;

struct C {
    const B& f() const { get }
    B& f() { get } 
private:
    D1 d1;
    D2 d2;
};

在这里你可以看到不同的版本f()应该返回相同的对象(在一种情况下是 const,在另一种情况下不是),基于一些选择逻辑,这可能非常复杂。示例中为了避免重复该逻辑的代码,通过#define.

f()是否可以在不借助预处理器服务的情况下避免不同版本中的代码重复?

c++
  • 4 4 个回答
  • 10 Views

4 个回答

  • Voted
  1. Vlad from Moscow
    2020-02-20T19:05:13Z2020-02-20T19:05:13Z

    你可以写类似下面的东西

    struct C {
        const B& f() const { if (s) return d1; else return d2; }
        B& f() { return const_cast<B &>( const_cast<const C *>( this )->f() ); } 
    private:
        D1 d1;
        D2 d2;
    };
    

    这是演示程序

    #include <iostream>
    
    struct B {};
    struct D1 : B {};
    struct D2 : B {};
    
    bool s;
    
    struct C {
        const B& f() const 
        {
            std::cout << "const B & f() const" << std::endl;
            if (s) return d1; else return d2; 
        }
        B& f() 
        { 
            std::cout << "B & f()" << std::endl;
            return const_cast<B &>( const_cast<const C *>( this )->f() ); 
        } 
    private:
        D1 d1;
        D2 d2;
    };
    
    int main() 
    {
        C c1;
        c1.f();
    
        std::cout << std::endl;
    
        const C c2;
        c2.f();
    
        return 0;
    }
    

    其输出到控制台

    B & f()
    const B & f() const
    
    const B & f() const
    
    • 8
  2. αλεχολυτ
    2020-02-20T19:33:20Z2020-02-20T19:33:20Z

    我想出了一个具有模板友好功能的变体:

    template<class R, class T>
    R& g(T* t);
    
    struct C {
        const B& f() const { return g<const B&>(this); }
        B& f() { return g<B&>(this); }
    private:
        D1 d1;
        D2 d2;
        template<class R, class T> 
        friend R& g(T* t);
    };
    
    template<class R, class T>
    R& g(T* t) {
        if (s) return t->d1; else return t->d2;
    }
    

    或者你甚至可以将它移到一个类中:

    struct C {
        const B& f() const;
        B& f();
    private:
        D1 d1;
        D2 d2;
        template<class R, class T> 
        static R& g(T* t) {
            if (s) return t->d1; else return t->d2;
        }
    };
    
    const B& C::f() const { return g<const B&>(this); }
    
    B& C::f() { return g<B&>(this); }
    

    并且由于类型R本质上可以从 中存在常量这一事实推导出来,因此T可以从模板中完全删除该类型:

    template<class T> 
    static std::conditional_t<std::is_const_v<T>, const B&, B&> g(T* t) {
        if (s) return t->d1; else return t->d2;
    }
    

    那。调用时无需明确指定类型g:

    const B& C::f() const { return g(this); }
    
    B& C::f() { return g(this); }
    
    • 5
  3. int3
    2020-02-21T03:32:16Z2020-02-21T03:32:16Z

    明显的选择:

    class A {
        bool flag;
        int a;
        int b;
    
    public:
        int& get() { return flag ? a : b; }
        const int& get() const { return ((A*)this)->get(); }
    };
    

    例子:

    int main()
    {
        A a {};
        const A ca {};
        static_assert(std::is_same<int&, decltype(a.get())>::value, "!!");
        static_assert(std::is_same<const int&, decltype(ca.get())>::value, "!!");
    }
    
    • 4
  4. Best Answer
    AnT stands with Russia
    2020-02-21T05:59:41Z2020-02-21T05:59:41Z

    出于稳定性考虑的代码重复问题通常有两种形式:

    1. 在单个函数级别:当有两个具有相同实现的函数时,不同之处仅在于输入类型的恒定性(作为一种特殊情况,包括*this类方法中的恒定性)和相应的返回值的恒定性。

      在 C 语言中,解决这个问题的一个著名习语是编写一个函数,在尊重输入数据的常量性的框架内解决问题,然后简单地无条件地从返回值中删除常量性(例如,参见标准函数strstr)。在这种情况下,假设调用代码知道数据恒常性的情况,将在适当的函数调用期间“绅士地”返回常量“丢失”。

      在C++语言中,这种做法在技术上也是适用的,但不习惯使用。更准确地说,传统的 C++ 惯用语在内部基于几乎相同的方法,在外部实现时略有不同:为函数的常量版本提供了完整的实现,为函数的第二个(非常量)版本提供了同样的功能建立在它之上。后者是通过 const 通过从返回值中删除 constness 来实现的

      const return_type *foo(const input_type *argument)
      {
        ...
      }
      
      return_type *foo(input_type *argument)
      {
        return const_cast<return_type *>(foo(const_cast<const input_type *>(argument));
      }
      

      这种方法非常适合您的情况。

    2. 在单个类的级别:代码需要实现两个类,从源代码的角度来看,这两个类实际上是相同的,只是所处理数据的外部稳定性不同。一个很好的例子是容器迭代器类的 const 和非常量版本。

      在这种情况下,一种可行的方法是将通用功能实现为用所需类型(在最简单的情况下为一个)参数化的模板类,并通过此模板的特化来实现所需的最终类。就像是

      template <typename T>
      class list 
      {
        template <typename U> class iterator_impl {
          ...
        };
      
        typedef iterator_impl<T> iterator;
        typedef iterator_impl<const T> const_iterator;
        ...
      };
      

    PS您自己使用模板函数的答案实际上是对上述第二种方法对第一种情况的改编。毫无疑问,它会起作用,但在这种情况下,在const_cast我看来,带有 的平庸选项看起来更简单、更合适。

    • 4

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5