【问题标题】:enable_if iterator as a default template parameter?enable_if 迭代器作为默认模板参数?
【发布时间】:2012-08-07 13:52:39
【问题描述】:

我有一个这样的构造函数:

class MyClass
{
    template<class TI> MyClass(TI first, TI last);
};

template<class TI> MyClass::MyClass(TI first, TI last)
{
    ;
}

我想仅当 TI 是一个迭代器时才启用这个构造函数(这意味着我认为 TI 有一个 iterator_category)。如何在 C++ 2011 中使用 enable_if 作为默认模板参数(在声明和定义中)?

非常感谢。

【问题讨论】:

    标签: c++ templates c++11 sfinae enable-if


    【解决方案1】:

    这取决于你想要什么。如果没有其他重载,则只需 nothing 就可以了。如果传递的类型未提供必要的操作,编译器将产生错误。

    如果你真的想将它限制为迭代器,最好使用static_assert,因为它会产生一个带有很好的自定义错误消息的错误,而不是“模棱两可的函数调用,这是我所有的无数重载可以找到:遵循无穷无尽的重载列表”或“找不到函数,请自行查找”。

    如果有另一个模板化重载冲突,那么你确实需要一些 enable_if 东西。我写了一篇关于using enable_if with C++11 features 的博客文章,以及为什么默认模板参数对此不是很好。我改用这样的方法解决了:

    enum class enabler {};
    
    template <typename Condition>
    using EnableIf = typename std::enable_if<Condition::value, enabler>::type;
    
    
    class MyClass
    {
        template<class TI, EnableIf<is_iterator<TI>>...> MyClass(TI first, TI last);
    };
    
    template<class TI, EnableIf<is_iterator<TI>>...> MyClass::MyClass(TI first, TI last)
    { /* blah */ }
    

    您现在需要的只是测试的特征。我认为测试iterator_category 的存在就足够了,但应该用std::iterator_traits 来完成,因为指针是迭代器,没有嵌套的typedef。

    这可以通过使用 SFINAE 的常用技术来完成。使用 C++11,我执行以下操作:

    template <typename T>
    struct sfinae_true : std::true_type {};
    
    struct is_iterator_tester {
        template <typename T>
        static sfinae_true<typename std::iterator_traits<T>::iterator_category> test(int);
    
        template <typename>
        static std::false_type test(...);
    };
    
    template <typename T>
    struct is_iterator : decltype(is_iterator_tester::test<T>(0)) {};
    

    话虽如此,这可以通过使用默认函数参数的传统技术来完成:

    class MyClass
    {
        template<class TI>
        MyClass(TI first, TI last,
                typename std::iterator_traits<T>::iterator_category* = nullptr)
    };
    
    template<class TI>
    MyClass::MyClass(TI first, TI last,
                     typename std::iterator_traits<T>::iterator_category*)
    { /* blah */ }
    

    【讨论】:

    • 感谢您如此清晰的总结。您关于默认参数模板可能存在的危险的博文非常有趣。
    • 也许是时候写一本关于“现代 C++”的书了?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-09
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多