2016-10-27 2 views
4

오늘 두 번째 컴파일러 오류로 인해 혼란 스럽습니다. 어떻게 든 아래의 코드에서 gcc는 코드가 반복자 return_iter을 반환하는 함수를 가지고 있다고 불평합니다. std::_Rb_tree_iterator<const int*> 다음에 std::_Rb_tree_const_iterator<const int*>이 있지만 const가 아니기 때문에 둘 다 const 반복자가 아니어야합니다. 누구든지 메서드가 non const lvalue에서 호출 될 때 const_iterator을 반환하는 이유를 설명 할 수 있습니까?std :: set iterators의 반환 유형이 충돌합니다.

전체 코드는 아래에 붙여 넣습니다.

참고gcc으로 컴파일 할 때만이 오류가 발생합니다. 나는 그 소리 (Apple LLVM version 8.0.0 (clang-800.0.38)와이를 컴파일 할 때이 오류가 표시되지 않습니다. 내가 사용하고있는 버전의 gcc가 g++ (GCC) 5.1.0

이와 관련된 질문입니다.이 앞으로의 올바른 사용인가?인가 당신이 원하는 때마다 std::forward 전화를 확인 간주 전달 참조를 사용? 내가 아래라고있는 이유는 유형이 객체가를 rvalue 때 몇 가지 방법을 과부하 단지의 경우입니다 ..


#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

BTW,'std :: end (std :: forward (container))'하지 마라. –

+0

@ T.C. 나는 그것에 대해 논평 할 사람을 찾고있었습니다! 그게 왜 나쁜지 설명해 주시겠습니까? 나는 그것에 대해 생각하고 있었고 나는 왜 그것을하지 말아야하는지에 대한 좋은 결론에 도달하지 못했습니다. – Curious

+0

자유로운'begin'과'end'는 rvalues와 함께 사용하도록 설계되지 않았으며, 주어진 값이 주어지면 올바르게 행동하지 않습니다. –

답변

5

이것은 std::set이 투명 비교기를 처리하는 방식의 libstdC++ 버그입니다. 여기에 짧은 예입니다 :

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

첫 번째 주장은 괜찮습니다, 우리는 iterator를 반환하는 lower_bound(Key const&)를 호출합니다. 두 번째 어설 션은 LessPtr이 투명하고 오버로드가 더 정확하기 때문에 (정확히 일치하므로) 함수 템플릿 template <class K> lower_bound(K const&)을 호출하고 있기 때문에 발생합니다. libstdC++의 경우 const_iterator을 반환합니다.

그러나 set_ptrsconst이 아니므로 안됩니다. 내가 제출 한 78134

+0

답변 해 주셔서 감사합니다! 정확히'a_tran '은 무엇입니까? – Curious

+0

나는 아직도 그것을 얻지 못한다. 나는 const_iterator를 반환하는'std :: end'와'lower_bound'를 호출하는 것이 보통의 반복자를 돌려주는 것이라고 생각한다. – Curious

+0

@Curious @Curious 이것은 모든 연관 컨테이너에 대한 요구 사항을 기술하는 데 사용되는 임의의 식별자이다. [큰 표] (http://eel.is/c++draft/associative.reqmts#tab:containers.associative.requirements). – Barry

관련 문제