C++ 不允许使用迭代器参数实例化函数模板

C++ 不允许使用迭代器参数实例化函数模板,c++,templates,visual-c++,c++14,function-templates,C++,Templates,Visual C++,C++14,Function Templates,我有一个函数模板,它采用模板参数: template <class R> RefT<R> make_ref(R& res) { return RefT<R>(&res); } 我想要防止R成为任何类型的迭代器,或者,如果这更容易,我想要有一个编译器更愿意用于迭代器的重载,该迭代器在迭代器取消引用的情况下再次调用make_ref 最好的方法是将两者结合起来,因此编译器更喜欢使用特定于迭代器的重载,而拒绝使用非特定版本 我希望代码的使用者

我有一个函数模板,它采用模板参数:

template <class R>
RefT<R> make_ref(R& res) {
    return RefT<R>(&res);
}
我想要防止R成为任何类型的迭代器,或者,如果这更容易,我想要有一个编译器更愿意用于迭代器的重载,该迭代器在迭代器取消引用的情况下再次调用make_ref

最好的方法是将两者结合起来,因此编译器更喜欢使用特定于迭代器的重载,而拒绝使用非特定版本


我希望代码的使用者能够调用make_refsomething,而不必考虑它是否是迭代器-如果是,我只需要做一些不同的事情,如果不可能,给使用者一个有用的错误消息。

首先,你可能需要根据自己的需求调整它:

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));
注意:使用std::iterator_traits可能是一个不错的选择

有了SFINAE,你可以

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
}
注意:由于您希望以不同的方式管理指针,除了自定义的is\u迭代器之外,我还使用std::is\u指针

注意:条件不应重叠,否则会产生冲突


首先,您可能需要根据自己的需求调整它:

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));
注意:使用std::iterator_traits可能是一个不错的选择

有了SFINAE,你可以

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
}
注意:由于您希望以不同的方式管理指针,除了自定义的is\u迭代器之外,我还使用std::is\u指针

注意:条件不应重叠,否则会产生冲突

我在这里使用了is_迭代器:

此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;
}
我在这里使用了is_迭代器:

此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;
}

这也可以通过将SFINAE与std::iterator_traits一起使用来实现,它将处理以前的答案处理具有内部iterator_category typedef的指针和类型的所有情况,但是:

无需编写自己的traits(如is_iterator)来实现这一点,或者至少大多数模板机制都封装在iterator_traits中

还可以处理潜在的用户定义迭代器,这些迭代器具有自己的迭代器特性专门化,而不使用通用迭代器类别typedef,不确定这是否相关/合法技术,但肯定是可能的


这也可以通过将SFINAE与std::iterator_traits一起使用来实现,它将处理以前的答案处理具有内部iterator_category typedef的指针和类型的所有情况,但是:

无需编写自己的traits(如is_iterator)来实现这一点,或者至少大多数模板机制都封装在iterator_traits中

还可以处理潜在的用户定义迭代器,这些迭代器具有自己的迭代器特性专门化,而不使用通用迭代器类别typedef,不确定这是否相关/合法技术,但肯定是可能的


你说的迭代器是什么意思?运算符*、++,等等指针?SIMEAE或标签调度是解决方案。我不完全确定,但我想我只是说了一个对C++中迭代器意味着什么的天真的理解,而不是那些可以被当作迭代器处理的东西,尽管如果处理这些情况也比较容易,那么它就会膨胀。但是,恐怕我不知道这是什么。@ LyndenShields Iterator在C++中指的是任何可以调用*和++的方法,并得到满足一些条件和/或其他事物的结果,基于迭代器类。运算符*、++,等等指针?SIMEAE或标签调度是解决方案。我不完全确定,但我想我只是说了一个对C++中迭代器意味着什么的天真的理解,而不是那些可以被当作迭代器处理的东西,尽管如果处理这些情况也比较容易,那么它就会膨胀。但是,恐怕我不知道这是什么。@ C++中的LyndenShields Iterator指的是任何可以调用*和++并获得满足一些条件和/或其他事物的结果,基于迭代器类别。我确实需要处理不同于迭代器的指针。另外,如果enable_不应该是R或RefT,那么第二个enable_是吗?我不知道想要的签名,但你应该知道:-@lyndensheelds指针不是迭代器?指针是指针iterator@LyndenShields:是,标准::如果启用,则启用T@LyndenShields:我添加了一个已修复std::decltype键入错误的指针。我确实需要以不同的方式处理不是迭代器的指针。另外,如果enable_不应该是R或RefT,那么第二个enable_是吗?我不知道想要的签名,但你应该知道:-@lyndensheelds指针不是迭代器?指针是指针iterator@LyndenShields:是,标准::如果启用,则启用T@LyndenShields:我添加了一个已修复std::decltype打字错误的。那么,你能在这里给出is_迭代器特征的适当定义吗?那么,你能在这里给出is_迭代器特征的适当定义吗?你能与公认的
回答?你能和公认的答案进行比较和对比吗?