【问题标题】:Why do boost/etc do so much SFINAE on template member functions' argument types?为什么 boost/etc 在模板成员函数的参数类型上做这么多 SFINAE?
【发布时间】:2016-03-15 02:54:31
【问题描述】:

当使用enable_if 等测试的参数不满足各种标准时,有选择地从类接口中删除模板成员函数的基本原理是什么?如果保留成员函数模板,尝试使用它们会失败,在我看来,在更复杂的情况下,编译器错误比“替换失败”更有用?

如果编译失败,支持这些极其严格的基于 SFINAE 的模板成员函数要求的论据是什么?

【问题讨论】:

    标签: c++ templates boost sfinae


    【解决方案1】:

    已发现模板代码中 2-5 深的编译器错误几乎是不可理解的。你会得到一堆模板噪音。

    SFINAE 替换失败通常会列出一个模板并说它不起作用,因为无法推断出某些参数,通常会显示失败的特征。不完美,但比模板喷射更好。

    更重要的是,这样的模板可以阻止其他有效的模板。

    此外,如果您使用类似 SFINAE 的技术,您可以测试给定方法是否存在并且在编译时是否有效;如果正文无法编译,则无法编译。

    【讨论】:

    • 也可以避免歧义,例如初始化变体等时(您几乎说“可以阻止其他有效的变体”)
    【解决方案2】:

    您觉得哪个错误消息更容易理解。这个是 SFINAE 的吗?

    template <class C, class = decltype(begin(std::declval<C&>())[0])>
    void sort_sfinae(C& c) {
        std::sort(c.begin(), c.end());
    }
    
    main.cpp: In function 'int main()':
    main.cpp:11:18: error: no matching function for call to 'sort_sfinae(std::__cxx11::list<int>&)'
         sort_sfinae(l);
                      ^
    main.cpp:5:6: note: candidate: template<class C, class> void sort_sfinae(C&)
     void sort_sfinae(C& c) {
          ^
    main.cpp:5:6: note:   template argument deduction/substitution failed:
    main.cpp:4:62: error: no match for 'operator[]' (operand types are 'std::__cxx11::list<int>::iterator {aka std::_List_iterator<int>}' and 'int')
     template <class C, class = decltype(begin(std::declval<C&>())[0])>
                                                                  ^
    

    或者这个没有?

    template <class C>
    void sort_no_sfinae(C& c) {
        std::sort(c.begin(), c.end());
    }
    
    In file included from /usr/local/include/c++/5.3.0/algorithm:62:0,
                     from main.cpp:2:
    /usr/local/include/c++/5.3.0/bits/stl_algo.h: In instantiation of 'void std::__sort(_RandomAccessIterator, _RandomAccessIterator, _Compare) [with _RandomAccessIterator = std::_List_iterator<int>; _Compare = __gnu_cxx::__ops::_Iter_less_iter]':
    /usr/local/include/c++/5.3.0/bits/stl_algo.h:4698:18:   required from 'void std::sort(_RAIter, _RAIter) [with _RAIter = std::_List_iterator<int>]'
    main.cpp:6:14:   required from 'void sort_no_sfinae(C&) [with C = std::__cxx11::list<int>]'
    main.cpp:11:21:   required from here
    /usr/local/include/c++/5.3.0/bits/stl_algo.h:1964:22: error: no match for 'operator-' (operand types are 'std::_List_iterator<int>' and 'std::_List_iterator<int>')
         std::__lg(__last - __first) * 2,
                          ^
    In file included from /usr/local/include/c++/5.3.0/bits/stl_algobase.h:67:0,
                     from /usr/local/include/c++/5.3.0/list:60,
                     from main.cpp:1:
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:328:5: note: candidate: template<class _Iterator> typename std::reverse_iterator<_Iterator>::difference_type std::operator-(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_Iterator>&)
         operator-(const reverse_iterator<_Iterator>& __x,
         ^
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:328:5: note:   template argument deduction/substitution failed:
    In file included from /usr/local/include/c++/5.3.0/algorithm:62:0,
                     from main.cpp:2:
    /usr/local/include/c++/5.3.0/bits/stl_algo.h:1964:22: note:   'std::_List_iterator<int>' is not derived from 'const std::reverse_iterator<_Iterator>'
         std::__lg(__last - __first) * 2,
                          ^
    In file included from /usr/local/include/c++/5.3.0/bits/stl_algobase.h:67:0,
                     from /usr/local/include/c++/5.3.0/list:60,
                     from main.cpp:1:
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:380:5: note: candidate: template<class _IteratorL, class _IteratorR> decltype ((__y.base() - __x.base())) std::operator-(const std::reverse_iterator<_Iterator>&, const std::reverse_iterator<_IteratorR>&)
         operator-(const reverse_iterator<_IteratorL>& __x,
         ^
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:380:5: note:   template argument deduction/substitution failed:
    In file included from /usr/local/include/c++/5.3.0/algorithm:62:0,
                     from main.cpp:2:
    /usr/local/include/c++/5.3.0/bits/stl_algo.h:1964:22: note:   'std::_List_iterator<int>' is not derived from 'const std::reverse_iterator<_Iterator>'
         std::__lg(__last - __first) * 2,
                          ^
    In file included from /usr/local/include/c++/5.3.0/bits/stl_algobase.h:67:0,
                     from /usr/local/include/c++/5.3.0/list:60,
                     from main.cpp:1:
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:1138:5: note: candidate: template<class _IteratorL, class _IteratorR> decltype ((__x.base() - __y.base())) std::operator-(const std::move_iterator<_Iterator>&, const std::move_iterator<_IteratorR>&)
         operator-(const move_iterator<_IteratorL>& __x,
         ^
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:1138:5: note:   template argument deduction/substitution failed:
    In file included from /usr/local/include/c++/5.3.0/algorithm:62:0,
                     from main.cpp:2:
    /usr/local/include/c++/5.3.0/bits/stl_algo.h:1964:22: note:   'std::_List_iterator<int>' is not derived from 'const std::move_iterator<_Iterator>'
         std::__lg(__last - __first) * 2,
                          ^
    In file included from /usr/local/include/c++/5.3.0/bits/stl_algobase.h:67:0,
                     from /usr/local/include/c++/5.3.0/list:60,
                     from main.cpp:1:
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:1145:5: note: candidate: template<class _Iterator> decltype ((__x.base() - __y.base())) std::operator-(const std::move_iterator<_Iterator>&, const std::move_iterator<_Iterator>&)
         operator-(const move_iterator<_Iterator>& __x,
         ^
    /usr/local/include/c++/5.3.0/bits/stl_iterator.h:1145:5: note:   template argument deduction/substitution failed:
    In file included from /usr/local/include/c++/5.3.0/algorithm:62:0,
                     from main.cpp:2:
    /usr/local/include/c++/5.3.0/bits/stl_algo.h:1964:22: note:   'std::_List_iterator<int>' is not derived from 'const std::move_iterator<_Iterator>'
         std::__lg(__last - __first) * 2,
                          ^
    In file included from /usr/local/include/c++/5.3.0/vector:65:0,
                     from /usr/local/include/c++/5.3.0/bits/random.h:34,
                     from /usr/local/include/c++/5.3.0/random:49,
                     from /usr/local/include/c++/5.3.0/bits/stl_algo.h:66,
                     from /usr/local/include/c++/5.3.0/algorithm:62,
                     from main.cpp:2:
    /usr/local/include/c++/5.3.0/bits/stl_bvector.h:208:3: note: candidate: std::ptrdiff_t std::operator-(const std::_Bit_iterator_base&, const std::_Bit_iterator_base&)
       operator-(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y)
       ^
    /usr/local/include/c++/5.3.0/bits/stl_bvector.h:208:3: note:   no known conversion for argument 1 from 'std::_List_iterator<int>' to 'const std::_Bit_iterator_base&'
    

    【讨论】:

    • 点了。如果实现了概念,它们会是多余的吗?
    • @experquisite SFINAE 基本上是我们能做的最好的概念破解版本。对于概念,错误将是even better。
    • @Barry 这有点取决于。如果我有两打重载,也许我更喜欢从我感兴趣的一个重载的内容中吐出一串错误,而不是两打主要是关于我不关心的重载的消息。
    猜你喜欢
    • 2020-10-03
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 2015-09-04
    • 1970-01-01
    • 2013-04-06
    相关资源
    最近更新 更多