【问题标题】:Overloading based on bool template parameter基于 bool 模板参数的重载
【发布时间】:2020-01-12 11:26:21
【问题描述】:

我有一个带有单个布尔模板参数的模板类。我希望能够从参数等于true 的实例隐式转换为等于false 的实例。

我试过这样做(对于复制构造函数),但问题是当我有Foo<true> 时,现在有两个版本的相同构造函数(具有相同的签名)。

template <bool B>
class Foo
{
public:
    Foo(const Foo& other);
    Foo(const Foo<true>& other);
};

不确定如何实现?我还打算为移动构造函数和赋值提供类似的代码。

【问题讨论】:

    标签: c++ templates overloading copy-constructor move-constructor


    【解决方案1】:

    您可以申请SFINAE,使Foo(const Foo&lt;true&gt;&amp; other)只对Foo&lt;false&gt;有效。

    template <bool B>
    class Foo
    {
    public:
        Foo(const Foo& other);
        template <bool b = B, std::enable_if_t<!b>* = nullptr> // when b is false
        Foo(const Foo<true>& other);
    };
    

    【讨论】:

      【解决方案2】:

      从 C++20 开始,您将能够编写如下内容:

      template<bool B>
      class Foo
      {
      public:
          Foo(const Foo& other) 
              : Foo(other, Tag{}) { }
      
          Foo(const Foo<true>& other) 
          requires(!B)               
              : Foo(other, Tag{}) { }
      
      private:
          struct Tag {};
      
          template<bool B1>
          Foo(const Foo<B1>& other, Tag) {
              // ...
          }
      };
      

      这里使用requires-clause 代替SFINAE(参见songyuanyao 的回答)。可以使用带有Tag 参数的私有构造函数来避免代码重复。您可能还需要让Foo&lt;true&gt; 成为Foo&lt;false&gt; 的朋友。

      【讨论】:

      • 这不是一个拷贝构造函数(Foo&lt;true&gt;(t) 调用一个隐式生成的,Foo&lt;false&gt;(f) 也会调用一个隐式生成的。只有Foo&lt;false&gt;(t) 调用这个构造函数)
      【解决方案3】:

      如果您需要区分Foo&lt;false&gt;Foo&lt;true&gt;,则无需使用enable_if。以下应该有效:

      template <bool B>
      class Foo
      {
      public:
          Foo(const Foo<true>& other);
          Foo(const Foo<false>& other);
          // ...
      };
      

      https://godbolt.org/z/_9NNhR


      在注释之后,为了禁止从 false 转换为 true,以下代码将起作用:

      template <bool B>
      class Foo
      {
      public:
          template<bool Other>
          Foo(const Foo<Other>& other) {}
          Foo() {}
      };
      
      template <>
      template <>
      Foo<true>::Foo(const Foo<false>&) = delete;
      

      https://godbolt.org/z/NjghXK


      如果我们想替换copy ctor,避免从假到真的转换:

      template <bool B>
      class Foo
      {
      public:
          Foo(const Foo<true>& other) {
              std::cout << true << " set to " << B << std::endl;
          }
          Foo(const Foo<false>& other) {
              std::cout << false << " set to " << B << std::endl;
          }
          Foo() {}
      };
      
      template <>
      Foo<true>::Foo(const Foo<false>&) = delete;
      

      https://godbolt.org/z/zt8VMb

      【讨论】:

      • 我不希望从 false 转换为 true。
      • @emil.indzhev 添加了另一个禁止从 false 转换为 true 的版本
      • 在第二个版本中你仍然需要定义一个拷贝构造函数Foo(const Foo&amp; other)。如果你不定义它,编译器会为你隐式生成一个,它会优先于模板化的。
      • @Evg,添加了另一个版本。这个想法是最终可以基于专业化实现在这种情况下,不需要enable_ifrequires
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-25
      • 2021-01-01
      • 2023-03-12
      • 1970-01-01
      • 2012-03-26
      相关资源
      最近更新 更多