【问题标题】:type signature of an enable_if'ed templated template constructor?enable_if'ed 模板化模板构造函数的类型签名?
【发布时间】:2011-07-05 08:57:08
【问题描述】:

我通常声明我的类和模板,然后定义它们的方法(当然是在同一个头文件中)。我只是觉得这样更容易阅读。好吧,我遇到了一个案例,我无法确定在类外定义中使用的工作类型签名。这是我正在做的一个简化示例,它说明了问题:

template <class T>
struct Foo
  {
    Foo(T a, T b);

    template 
      < class Iterator
      , enable_if< is_iterator<Iterator> >
      >
    Foo
      ( Iterator first
      , Iterator last
      );
  };

template <class T>
Foo<T>::Foo(T a, T b)
{ ... }

template <class T>
template
  < class U
  , WHAT_GOES_HERE?
  >
Foo<T>::Foo(U f, U l)
{ ... }

我在WHAT_GOES_HERE 插槽中尝试了很多方法来尝试获得匹配的签名,但我一直失败。我需要 enable_if 来区分一个传入两个 T 类型对象的情况,以及一个传入一对迭代器的情况。如果模板化的构造函数是在主模板中定义的,则代码可以正常工作,这就是代码当前的工作方式,但我更愿意将定义移到声明之外。

编辑:我应该提一下,我不能只在定义中重复使用 enable_if<...>,因为 enable_if<...> 为其类型分配了一个默认值,它你不能在一个不是声明的定义中做。

【问题讨论】:

  • 你真的需要 SFINAE 吗?如果你只是将第二个构造函数声明为template &lt;typename U&gt; Foo(U first, U last);,那么如果调用者传递了两个T 类型的对象,则仍然会选择第一个构造函数。
  • Type T 通常是算术类型,我希望能够在 T 无符号时传入整数,反之亦然,并且不调用模板化构造函数(这在我之前已经发生过)使用了 enable_if)
  • 实际上,您根本没有分配默认值。模板的第二个参数是enable_if&lt; is_iterator&lt; FirstParam &gt; &gt;。有点像如果您期望int。它不应该编译,当然也不可能使用。
  • 我不清楚。 enable_if 为其模板参数分配默认类型,这是分配默认值的元版本。
  • 模板默认参数如下所示:template &lt; typename T, typename T2 = xxxx &gt;

标签: c++ templates boost constructor enable-if


【解决方案1】:
template <class T>
struct Foo
  {
    Foo(T a, T b);

    template <class Iterator
      ,       class = typename std::enable_if
                       <is_iterator<Iterator>::value>
                       ::type
      >
    Foo
      ( Iterator first
      , Iterator last
      );
  };

template <class T>
Foo<T>::Foo(T a, T b)
{  }

template <class T>
template
  < class U
  , class >
Foo<T>::Foo(U f, U l)
{  }

【讨论】:

  • 这个我试过了,还是不行。我收到一条消息,说该定义与我的模板中的任何声明都不匹配。虽然,我必须说,这应该工作!
  • 我用g++-4.4和clang对其进行了测试。但是我有 -std=c++0x 用于我的测试,现在我仔细检查,我认为这是必需的。没有它,clang 会给出以下警告:警告:函数模板的默认模板参数是 C++0x 扩展 [-Wc++0x-extensions] ,class= typename std::enable_if
  • 奇怪,当我用我的编译器尝试时,你的示例确实有效。但是当我在真实模板上尝试同样的事情时,我得到了一个错误。我一定是做错了什么……
  • 忘记“::value”或“::type”是很容易犯的错误。
【解决方案2】:

你可以做的最简单的事情是:

template<class Iterator>
Foo
  ( Iterator first
  , typename enable_if<is_iterator<Iterator>, Iterator>::type last
  );

【讨论】:

    【解决方案3】:

    我不会那样做。以下是我要做的更改:

    template <class T>
    struct Foo
      {
        Foo(T a, T b);
    
        template 
          < class Iterator
          >
        Foo
          ( Iterator first
          , Iterator last
          , typename enable_if<is_iterator<Iterator> >::type* = 0
          );
      };
    
    template <class T>
    Foo<T>::Foo(T a, T b)
    { ... }
    
    template <class T>
    template
      < class U
      >
    Foo<T>::Foo(U f, U l, typename enable_if< is_iterator<U> >::type*)
    { ... }
    

    这直接来自enable_if 的文档。

    【讨论】:

    • 有趣,我已经多次阅读 enable_if 文档,但我从未想过将构造函数视为嵌套函数...如果可行,那么它绝对可以接受。
    • 参见boost.org/doc/libs/1_46_0/libs/utility/enable_if.html 第 3 节:“构造函数和析构函数没有返回类型;额外的参数是唯一的选择。”
    • 谢谢!这确实起到了作用。这是否意味着我之前尝试的内容是不可能的,因为没有办法给出满足 C++ 的类型签名?
    • 您应该能够通过使用相同的参数信息简单地进行声明。但是,您永远无法使用它。另一方面,我没想到它会接受那种类型作为参数并编译。我很确定这是为数字类型保留的。
    • 使用相同的参数信息会产生错误,因为enable_if的定义有一个默认的模板参数,但现在想来,那不应该是个问题,虽然它在我的编译器上生成错误(g++ 4.5)
    【解决方案4】:

    这是您想要完成的任务吗? [我没有 is_iterator 类型特征,因此我使用 C++0x 类型特征和实用程序库重新设计了您的示例。它应该与 TR1 和 Boost 库以相同的方式工作。]

    #include <utility>
    #include <type_traits>
    
    template <typename T>
    struct S
    {
        // Constructor (1)
        S(T, T); 
    
        // Constructor (2)
        template <typename U>
        S(U, U, typename std::enable_if<std::is_integral<U>::value>::type* = 0);
    };
    
    template <typename T>
    S<T>::S(T, T)
    { }
    
    template <typename T>
    template <typename U>
    S<T>::S(U, U, typename std::enable_if<std::is_integral<U>::value>::type*)
    { }
    
    int main()
    {
        S<double> a(1.0, 2.0); // uses (1)
        S<double> b(1, 2);     // uses (2)
    }
    

    【讨论】:

    • 是的,这或多或少是正确的。我必须编写自己的 is_iterator。我不知道为什么它在 boost 中不是标准的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-02
    • 2011-05-24
    • 1970-01-01
    相关资源
    最近更新 更多