C++ 如果';模板化模板构造函数?

C++ 如果';模板化模板构造函数?,c++,templates,boost,constructor,enable-if,C++,Templates,Boost,Constructor,Enable If,我通常声明我的类和模板,然后在之后定义它们的方法(当然是在同一个头文件中)。我只是觉得那样读起来更容易。好吧,我遇到了一个例子,在这个例子中,我无法找出一个在类外定义中使用的工作类型签名。下面是我正在做的一个简化示例,它说明了问题: template <class T> struct Foo { Foo(T a, T b); template < class Iterator , enable_if< is_iterator

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

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)
{ ... }
模板
结构Foo
{
Foo(ta,tb);
模板

>
福
(迭代器优先)
,迭代器last
);
};
模板
Foo::Foo(ta,tb)
{ ... }
模板
模板

Foo::Foo(U f,U l)
{ ... }
我在
WHAT\u GOES\u HERE
槽中尝试了许多方法,试图获得匹配的签名,但我一直失败。我需要enable_if来区分一个传入两个类型为T的对象的情况,以及一个传入一对迭代器的情况。如果模板化构造函数是在主模板中定义的,那么代码就可以正常工作,这就是代码当前的工作方式,但是我更愿意将定义移到声明之外


EDIT:我应该提到,我不能在定义中重复使用enable\u if,因为enable\u if为其类型指定了一个默认值,而这在一个不是声明的定义中是无法做到的。

这就是您想要实现的吗?[我没有
is_迭代器
类型特征,因此我使用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)
}
#包括
#包括
模板
结构
{
//建造师(1)
S(T,T);
//建造师(2)
模板
S(U,U,typename std::enable_if::type*=0);
};
模板
S::S(T,T)
{ }
模板
模板
S::S(U,U,typename std::enable_if::type*)
{ }
int main()
{
sa(1.0,2.0);//使用(1)
sb(1,2);//使用(2)
}

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

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*)
{ ... }
模板
结构Foo
{
Foo(ta,tb);
模板

福
(迭代器优先)
,迭代器last
,如果::type*=0,则typename启用
);
};
模板
Foo::Foo(ta,tb)
{ ... }
模板
模板

Foo::Foo(如果::type*,则启用类型名)
{ ... }

这是
enable\u if

的直接文档,您可以做的最简单的事情是:

template<class Iterator>
Foo
  ( Iterator first
  , typename enable_if<is_iterator<Iterator>, Iterator>::type last
  );
模板
福
(迭代器优先)
,typename enable_if::type last
);
模板
结构Foo
{
Foo(ta,tb);
模板
福
(迭代器优先)
,迭代器last
);
};
模板
Foo::Foo(ta,tb)
{  }
模板
模板

Foo::Foo(U f,U l)
{  }

您真的需要SFINAE吗?如果您只是将第二个构造函数声明为
templatefoo(U first,U last)
,如果调用方传递两个类型为
T
的对象,则仍将选择第一个构造函数。类型T通常是算术类型,我希望能够在T未签名时传入int,反之亦然,并且不会调用模板构造函数(在我使用enable\u if之前发生过这种情况),您根本没有指定默认值。模板的第二个参数是
enable\if
。有点像你期望的
int
。它不应该编译,当然也不可能使用。我不清楚。enable\u if为其模板参数指定默认类型,这是指定默认值的元版本。模板默认参数如下所示:
template
有趣的是,我已经多次阅读了enable\u if文档,我从没想过把构造函数当作嵌套函数。。。如果这是可行的,那么它肯定是可以接受的。请参阅第3节:“构造函数和析构函数没有返回类型;额外的参数是唯一的选项。”谢谢!这确实奏效了。这是否意味着我之前尝试的是不可能的,因为没有办法给出一个满足C++的类型签名?您应该能够通过使用相同的参数信息来简单地声明。但你永远也不会使用它。另一方面,我没想到它会接受这种类型作为参数并编译。我很确定这是保留给数值类型的。使用相同的参数信息会产生错误,因为enable_if的定义有一个默认的模板参数,但现在我想起来了,这不应该是一个问题,尽管它会在我的编译器(g++4.5)上生成一个错误,我已经尝试过了,但它不起作用。我收到一条消息,说定义与模板中的任何声明都不匹配。虽然,我必须说,这应该行得通!我用g++-4.4和clang测试了它。然而,我的测试使用了-std=c++0x,现在我进行了双重检查,我认为这是必需的。如果没有它,clang会给出以下警告:警告:函数模板的默认模板参数是C++0x扩展[-Wc++0x扩展],class=typename std::enable\u如果奇怪,当我用编译器尝试时,您的示例确实有效。但当我在真实的模板上尝试同样的事情时,我得到了一个错误。我一定是做错了什么……忘记“::value”或“::type”是一个很容易犯的错误。是的,这或多或少是正确的。我必须编写自己的is_迭代器。我不知道为什么它在boost中不是标准的。
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)
{  }