我想编写一个函数,它为迭代器类型和其他类型打印不同的值。在做了一些研究之后,我想出了这个:
#include <iostream>
#include <iterator>
#include <experimental/type_traits>
namespace details
{
template <class T, class = void>
struct is_iterator : std::false_type
{
};
template <class T>
struct is_iterator<T, std::experimental::void_t<typename std::iterator_traits<T>::value_type>> : std::true_type
{
};
template <class T>
constexpr auto is_iterator_v = is_iterator<T>::value;
}
template <class T>
std::enable_if_t<!details::is_iterator_v<T>> print(const T &value)
{
std::cout << value;
}
template <class T>
std::enable_if_t<details::is_iterator_v<T>> print(const T &value)
{
std::cout << "(IteratorTo ";
print(*value);
std::cout << ')';
}
但我认为我的代码有点太长而且有点复杂。是否可以使我的代码更短更清洁?
答案 0 :(得分:3)
SFINAE是你的朋友:
template <class T>
constexpr std::true_type is_iterator(typename std::iterator_traits<T>::value_type*, int)
{
return {};
}
template <class T>
constexpr std::false_type is_iterator(void*, long)
{
return {};
}
template <class T>
constexpr auto is_iterator_v = is_iterator<T>(nullptr, 0);
此外,使用标记调度的print
的替代实现,您可能会或可能不会发现更具可读性:
template <class T>
void print(const T &);
namespace details
{
template <class T>
void print(const T &value, std::false_type)
{
std::cout << value;
}
template <class T>
void print(const T &value, std::true_type)
{
std::cout << "(IteratorTo ";
print(*value);
std::cout << ')';
}
}
template <class T>
void print(const T &value)
{
details::print(value, details::is_iterator_v<T>);
}
答案 1 :(得分:0)
我觉得你的解决方案简单,简洁,干净。
我只看到一个问题:您标记了您的问题C ++ 14,但您建议使用std::experimental::void_t
的代码......嗯......实验性而且永远不可用。
但是(如果我没错),使用旧的decltype逗号技巧,你可以在没有void_t
的情况下获得相同的结果。
您可以按如下方式编写std::true_type
版本(修改后尝试更正Ildjarn指出的问题(谢谢!)):
template <typename T>
struct is_iterator<T,
decltype(std::declval<typename std::iterator_traits<T>::value_type>(),
void())> : std::true_type
{ };
此解决方案也适用于C ++ 11。