Is it possible to specialize an Iterator template parameter by its value_type
?
I have a function with the following prototype.
template<typename InputIterator>
void f(InputIterator first, InputIterator last);
And I want to handle specially if InputIterator::value_type
is SomeSpecificType.
You can use some intermediate structs to get the partial template specialisation that you need. Something like this should do the trick
template<typename T, typename V>
struct f_impl
{
static void f( T first, T last ) {...}; //Default version
};
template<typename T>
struct f_impl<T, SomeSpecificType>
{
static void f(T first,T last) {...}; //Specialisation
};
template<typename InputIterator> void f(InputIterator first, InputIterator last)
{
f_impl<
InputIterator,
typename std::iterator_traits<InputIterator>::value_type
>::f(first,last);
};
Using SFINAE, assuming enable_if[_c]
and is_same
are either from Boost or <type_traits>
(and are appropriately qualified with either boost::
or std::
respectively):
template<typename InputIterator>
typename enable_if<
!is_same<
typename std::iterator_traits<InputIterator>::value_type,
SomeSpecificType
>::value
>::type
f(InputIterator first, InputIterator last)
{
// Default implementation.
}
template<typename InputIterator>
typename enable_if<
is_same<
typename std::iterator_traits<InputIterator>::value_type,
SomeSpecificType
>::value
>::type
f(InputIterator first, InputIterator last)
{
// Special case
}
In the Boost case, use boost::enable_if_c
for something similar to the above. You can use boost::enable_if
and get rid of the ::value
but then must also use eg boost::disable_if
.
How about:
template<typename T>
typename std::enable_if<std::is_same<typename T::value_type, SomeType>::value, void>::type
f(T first, T second);
This will work. This type of specialization only works with structs, so I can't do this with a function.
template <typename InputIterator, typename ValueType = typename InputIterator::value_type>
struct foobar
{
static void invoke(InputIterator first, InputIterator second)
{
// ...
}
};
template <typename InputIterator>
struct foobar<InputIterator, SomeSpecificType>
{
static void invoke(InputIterator first, InputIterator second)
{
// ...
}
};
This shouldn't require you to set the type. It should be inferred automatically.
Call me naive, but why wouldn't the following suffice?
struct MyType; // the only type I want
#include <iterator>
typedef std::iterator<std::input_iterator_tag, MyType> MyIt;
void f(const MyIt & begin, const MyIt & end)
{
/* ... */
}
OK, forget that above, that was nonsense. Here's a way to do it, which is just Luc's correct answer from above, for C++0x:
#include <vector>
#include <iterator>
#include <type_traits>
// "int" is our desired iterator value type, "void" is f's return type.
template <typename It>
typename std::enable_if<std::is_same<int, typename std::iterator_traits<It>::value_type>::value, void>::type
f(const It & begin, const It & end) { /* your function here */ }
int main()
{
std::vector<double> x;
std::vector<int> y;
//f(x.cbegin(), x.cend()); // error
f(y.cbegin(), y.cend()); // works
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.