I usually declare my classes and templates, and then define their methods after (in the same header file, of course). I just find it easier to read that way. Well, I've come across a case where I can't figure out a working type signature to use in an out-of-class definition. Here's a simplified example of what I'm doing, that illustrates the problem:
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)
{ ... }
I have tried a number of things in the WHAT_GOES_HERE
slot to try to get a matching signature, and I keep failing. I need the enable_if to distinguish the case where one passes in two objects of type T, and when one passes in a pair of Iterators. The code works fine if the templated constructor is defined inside the main template, which is how the code currently does it, but I'd much rather move the definition outside the declaration.
EDIT: I should mention that I can't just re-use enable_if<...> in the definition, because enable_if<...> assigns a default value for its type, which you cannot do in a definition that isn't also a declaration.
I wouldn't do it that way. Here's the changes I would make:
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*)
{ ... }
This is straight out of the documentation for enable_if
.
Is this what you are trying to accomplish? [I don't have an is_iterator
type trait, so I've reworked your example using the C++0x type traits and utility libraries. It should work the same way with the TR1 and Boost libraries.]
#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)
}
The simplest you can do is:
template<class Iterator>
Foo
( Iterator first
, typename enable_if<is_iterator<Iterator>, Iterator>::type last
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With