Как специализировать итератор по его типу значения в C++?
можно ли специализировать параметр шаблона итератора по его value_type
?
у меня есть функция со следующим прототипом.
template<typename InputIterator>
void f(InputIterator first, InputIterator last);
и я хочу обрабатывать специально, если InputIterator::value_type
и SomeSpecificType.
5 ответов
вы можете использовать некоторые промежуточные структуры, чтобы получить частичную специализацию шаблона, которая вам нужна. Что-то вроде этого должно сделать трюк
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);
};
С помощью SFINAE, предполагая, что enable_if[_c]
и is_same
либо из Boost, либо <type_traits>
(и имеют соответствующую квалификацию либо boost::
или std::
соответственно):
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
}
в случае наддува используйте boost::enable_if_c
для чего-то подобного выше. Вы можете использовать boost::enable_if
и избавиться от ::value
но тогда также должен использовать, например,boost::disable_if
.
Как насчет:
template<typename T>
typename std::enable_if<std::is_same<typename T::value_type, SomeType>::value, void>::type
f(T first, T second);
Это будет работать. Этот тип специализации работает только со структурами, поэтому я не могу сделать это с функцией.
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)
{
// ...
}
};
для этого не требуется устанавливать тип. Это должно быть выведено автоматически.
Назовите меня наивным,но почему бы не достаточно следующего?
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)
{
/* ... */
}
хорошо, забудьте, что выше, это была ерунда. Вот способ сделать это, который является правильным ответом люка сверху, для 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
}