我有一个函数模板,它采用模板化参数:
template <class R>
RefT<R> make_ref(R& res) {
return RefT<R>(&res);
}
我想要阻止R
成为任何类型的迭代器,或者,如果这更容易,我希望有一个重载,编译器将更喜欢用于迭代器,再次使用迭代器重新调用make_ref
最好的方法是将两者结合起来,因此编译器更喜欢使用迭代器特定的重载,并拒绝使用非特定版本。
我希望代码的使用者能够调用make_ref(something)
而不必考虑something
是否是迭代器 - 如果是,我只需要做一些不同的事情,并且如果不可能,请向消费者提供有用的错误消息。
答案 0 :(得分:4)
首先是特征(你可能需要根据你的要求进行调整):
<property name="name" type="string">
<meta attribute="use-in-tostring">true</meta>
<meta attribute="use-in-equals">true</meta>
</property>
注意:使用template <typename T>
auto is_iterator_impl(T* it)
-> decltype(**it, ++(*it), (*it) == (*it), std::true_type());
template <typename T>
auto is_iterator_impl(...) -> std::false_type;
template <typename T>
using is_an_iterator = decltype(is_iterator_impl<T>(0));
可能是一个不错的选择。
使用SFINAE,您可以
std::iterator_traits<IT>
注意:由于您希望以不同方式管理指针,除了自定义template <class R>
std::enable_if_t<!is_an_iterator<R>::value, RefT<R>>
make_ref(R& res) {
return RefT<R>(&res);
}
template <class R>
std::enable_if_t<is_an_iterator<R>::value && !std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
template <class R>
std::enable_if_t<std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
之外,我还使用std::is_pointer
。
注意:条件不应该重叠,否则就会发生冲突。
答案 1 :(得分:2)
我在这里使用is_iterator
:https://stackoverflow.com/a/4336298/678093
此traits结构与SFINAE一起使用,仅为非迭代器类型启用make_ref
:
#include <type_traits>
template<class T>
struct is_iterator
{
static T makeT();
typedef void * twoptrs[2]; // sizeof(twoptrs) > sizeof(void *)
static twoptrs & test(...); // Common case
template<class R> static typename R::iterator_category * test(R); // Iterator
template<class R> static void * test(R *); // Pointer
static const bool value = sizeof(test(makeT())) == sizeof(void *);
};
// just to make it compile
template <typename R>
struct RefT{};
template <class R, typename std::enable_if<!is_iterator<R>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
int main()
{
int* a;
make_ref(a); // fails to compile
int b;
make_ref(b); // compiles once RefT is correct
return 0;
}
alernative解决方案是使用std::iterator_traits
:
template <class R, typename std::enable_if<std::is_same<typename std::iterator_traits<R>::value_type, void>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
答案 2 :(得分:0)
这也可以通过使用std::iterator_traits
的SFINAE来完成,将处理以前答案处理的所有情况(指针和类型具有internal
iterator_category
typedef
)但是:< / p>
无需编写自己的特征(如is_iterator
)来执行此操作,或者至少大部分模板机制都封装在iterator_traits
还可以处理具有自己iterator_traits
专业化的潜在用户定义迭代器,而不使用泛型iterator_category
typedef
,不确定这种相关/法律技术是否可行