2016-10-27 51 views
4

这是今天的第二个编译器错误,让我感到困惑。不知何故,下面的代码,gcc抱怨代码的函数返回一个迭代器return_iter返回冲突类型std::_Rb_tree_iterator<const int*>然后std::_Rb_tree_const_iterator<const int*>,但它们都不应该是const迭代器,因为该集合不是const。任何人都可以解释为什么在非const左值上调用std::end()方法返回const_iteratorstd :: set迭代器的冲突返回类型

完整的代码粘贴在下面。

注意我只有在与gcc编译时才会出现此错误。此错误不会显示出来,当我编译这段铿锵(Apple LLVM version 8.0.0 (clang-800.0.38)。我使用的gcc版本是g++ (GCC) 5.1.0

一个相关的问题。这是正确的使用着的?是不是考虑行调用std::forward只要你想使用转发引用吗?我之所以把它称为以下是以防万一的类型重载一些方法,当对象是右值..


#include <vector> 
#include <string> 
#include <set> 
#include <iostream> 
using namespace std; 

int global_value = 1; 

class LessPtr { 
public: 

    template <typename PointerComparableOne, typename PointerComparableTwo> 
    constexpr auto operator()(PointerComparableOne&& lhs, 
           PointerComparableTwo&& rhs) const { 
     return *std::forward<PointerComparableOne>(lhs) < 
      *std::forward<PointerComparableTwo>(rhs); 
    } 

    using is_transparent = std::less<void>::is_transparent; 
}; 

template <typename Container, typename Key> 
auto return_iter(Container&& container, Key&& key) { 
    if (global_value == 1) { 
     return std::forward<Container>(container).lower_bound(std::forward<Key>(key)); 
    } 
    else { 
     return std::end(std::forward<Container>(container)); 
    } 
} 

void do_stuff(std::set<const int*, LessPtr>& set_ptrs) { 
    // auto value = string{"something"}; 
    auto value = 1; 
    auto iter = return_iter(set_ptrs, &value); 
    cout << reinterpret_cast<void*>(&iter) << endl; 
} 

int main() { 
    std::set<const int*, LessPtr> set_ptrs; 
    do_stuff(set_ptrs); 

    return 0; 
} 

以某种方式所需的LessPtr导致此错误。 。

+0

顺便说一句,不要做'std :: end(std :: forward (container))''。 –

+0

@ T.C。我正在寻找某人对此发表评论!你能解释为什么那么糟糕?我正在考虑这个问题,不能得出一个好的结论,为什么我不应该那样做 – Curious

+0

免费的'begin'和'end'不是用于rvalues的,并且如果给定的话不能正确运行。 –

回答

5

这是一个libstdC++ bug,处理透明比较器的方式是std::set。这里有一个更短的例子:

int main() { 
    using S = std::set<const int*, LessPtr>; 
    S set_ptrs; 

    int i = 0; 
    const int ci = 0; 
    static_assert(std::is_same< 
      decltype(set_ptrs.lower_bound(&ci)), S::iterator>{}, "!"); // OK 
    static_assert(std::is_same< 
      decltype(set_ptrs.lower_bound(&i)), S::iterator>{}, "!"); // Error 

    return 0; 
} 

的第一个断言是好的,我们称之为lower_bound(Key const&),它返回一个iterator。第二个断言触发是因为我们调用函数模板template <class K> lower_bound(K const&),因为LessPtr是透明的,并且该过载是更好的匹配(因为它是完全匹配),并且那个对于libstdC++返回const_iterator

set_ptrs不是const,所以它不应该是。我提交78134

+0

感谢您的回答!什么是“a_tran”? – Curious

+0

我还是不明白。我认为它的'std :: end'是返回const_iterator和调用'lower_bound'返回一个普通的迭代器,而不是其他方式 – Curious

+0

@Curious它是一个任意的标识符,用于描述所有关联容器的需求[大表](http://eel.is/c++draft/associative.reqmts#tab:containers.associative.requirements)。 – Barry

相关问题