【问题标题】:Disable member functions and variables without using inheritance or class specialization在不使用继承或类特化的情况下禁用成员函数和变量
【发布时间】:2017-11-28 17:43:11
【问题描述】:

我有一个模板类Foo,它有两种变体:一种有一个额外的模板类型参数。当该参数存在时,我希望该类具有一些附加功能,即在类中存储一个成员变量,并为其提供一些 getter 和 setter。我还需要对附加类型执行额外的static_assert(),我还需要禁用常规构造函数并提供一个也具有该类型参数的构造函数。它看起来像这样:

template <class Irrelevant, class Extra>
class Foo {
    //other stuff...
    static_assert(is_good_v<Extra>);
    Extra extra;
public:
    //other stuff...
    Foo(Irrelevant i) {/* irrelevant */}

    //now methods I need to enable only when Extra is present
    Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}
    void setExtra(Extra e) {extra = e;}
    void getExtra() {return extra;}
};

我尝试了几种方法,但似乎都没有令人满意。首先我尝试使用继承:

template <class Irrelevant>
class Bar {
    //other stuff...
public:
    //other stuff...
    Foo(Irrelevant i) {/* irrelevant */}
};

template <class Irrelevant, class Extra>
class Foo : public Bar<Irrelevant> {
    static_assert(is_good_v<Extra>);
    Extra extra;
public:
    Foo(Irrelevant i, Extra e) : Bar<Irrelevant>(i), extra(e) {/* irrelevant */}
    void setExtra(Extra e) {extra = e;}
    void getExtra() {return extra;}
};

template <class Irrelevant>
class Foo : public Bar<Irrelevant> {};

这(或至少类似的东西)单独工作,但在其他地方对它们进行模板检查时需要额外的解决方法,而且它不必要地乱扔全局命名空间,我不应该这样做。 第二种方法是对Foo 进行专门化,如下所示:

template <class Irrelevant, class... T>
class Foo {};

template <class Irrelevant, class Extra>
class Foo<Irrelevant, Extra> {
    //other stuff...
    static_assert(is_good_v<Extra>);
    Extra extra;
public:
    //other stuff...
    Foo(Irrelevant i) {/* irrelevant */}

    //now methods I need to enable only when Extra is present
    Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}
    void setExtra(Extra e) {extra = e;}
    void getExtra() {return extra;}
};


template <class Irrelevant>
class Foo<Irrelevant> {
    //other stuff...
public:
    //other stuff...
    Foo(Irrelevant i) {/* irrelevant */}
};

这也有效,并没有乱扔全局命名空间,但是所有的 //other stuff 都被复制了,这不是很好。我想尝试的第三种方法是 std::enable_if 所有这些东西,但我似乎无法让它工作。我尝试过这样的事情:

template <class Irrelevant, class Extra = void>
class Foo {
    //other stuff...
    static constexpr bool hasExtra = std::is_same_v<Extra, void>;
    static_assert(!hasExtra || is_good_v<Extra>);
    std::conditional<hasExtra, Extra, bool> extra;
public:
    //other stuff...
    template <typename = typename std::enable_if_t<!hasExtra>>
    Foo(Irrelevant i) {/* irrelevant */}

    //now methods I need to enable only when Extra is present
    template <typename = typename std::enable_if_t<hasExtra>>
    Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}

    template <typename = typename std::enable_if_t<hasExtra>>
    void setExtra(Extra e) {extra = e;}

    template <typename = typename std::enable_if_t<hasExtra>>
    void getExtra() {return extra;}
};

但这显然不起作用,因为它会生成一个编译错误,因为在编译 getter 和 setter 时,SFINAE 没有其他函数可以让 SFINAE 进入。并为 Extra == void 添加虚拟函数将使有人使用这些函数的代码编译。我怎样才能正确地做到这一点?

【问题讨论】:

  • 如果你需要 mixins 而不是使用CRTP
  • 我可以,但正如我所写,我不希望将除 Foo 之外的任何名称引入全局命名空间。
  • 这如何迫使 mixin 类存在于全局命名空间中?只需根据需要添加另一层间接和enable_if()

标签: c++ c++17 variadic-templates sfinae template-specialization


【解决方案1】:

Foo 仅具有 extra 并且继承自部分专业化(例如 Foo&lt;Irrelevant, void&gt;)的公共部分怎么样?

我的意思是:类似

// with extra only
template <typename Irrelevant, typename Extra>
class Foo : public Foo<Irrelevant, void>
 {
   private:
      Extra extra;

      static_assert(is_good_v<Extra>);

   public:
      // to make visible the inherited constructor(s)
      using Foo<Irrelevant, void>::Foo;

      // to disable (?) a specific inherited constructor
      // Foo(Irrelevant i) = delete;

      //now methods I need to enable only when Extra is present
      Foo(Irrelevant i, Extra e) : extra(e) {/* irrelevant */}

      void setExtra(Extra e) {extra = e;}

      Extra getExtra() {return extra;}
 };

// common part, no extra
template <typename Irrelevant>
class Foo<Irrelevant, void>
 {
   public:
      Foo(Irrelevant i) {/* irrelevant */}
 };

【讨论】:

  • 太好了,我不知道模板专业化可以从同一模板的另一个专业化继承,谢谢!
  • @Joald - 我也是:我几天前才发现它,现在我正在广泛使用它。
猜你喜欢
  • 2012-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-13
  • 2023-01-15
相关资源
最近更新 更多