2016-07-09 5 views
9

호환 유형의 std::tuple에서 요소 별로 std::tuple 개 요소를 초기화 할 수 없습니다. boost::tuple처럼 작동하지 않는 이유는 무엇입니까?std :: tuple을 호환 유형의 std :: tuple로 요소별로 생성 할 수없는 이유는 무엇입니까?

#include <tuple> 
#include <boost/tuple/tuple.hpp> 

template <typename T> 
struct Foo 
{ 
    // error: cannot convert 'std::tuple<int>' to 'int' in initialization 
    template <typename U> 
    Foo(U &&u) : val(std::forward<U>(u)) {} 

    T val; 
}; 

int main() 
{ 
    boost::tuple<Foo<int>>{boost::tuple<int>{}}; // ok 

    auto a = boost::tuple<int>{}; 
    boost::tuple<Foo<int>>{a};      // ok 

    std::tuple<Foo<int>>{std::tuple<int>{}};  // fails with rvalue 

    auto b = std::tuple<int>{}; 
    std::tuple<Foo<int>>{b};      // fails with lvalue 
} 

Live on Coliru


std::tuple이 요소 현명한 건축 일을하지 않습니다 (GCC 또는 연타와 된 libstdC++ 컴파일되지 않습니다, 그러나 연타와의 libc는 ++ 오류없이 컴파일) 그리고 Foo<int>::Foo<std::tuple<int>> 대신 Foo<int>::Foo<int> 인스턴스화 . 내가 생각 std::tuple::tuple overloads no. 4 and 5는 그 목적을 위해 정확했다 :

template <class... UTypes> 
tuple(const tuple<UTypes...>& other); 

template <class... UTypes> 
tuple(tuple<UTypes...>&& other); 

참고 :
std::is_constructible<Ti, const Ui&>::value 모든 i에 대한 true하지 않는 한

가 오버로드 확인에 참여하지 않습니다.

std::is_constructible<Foo<int>, int>::valuetrue입니다. GCC 템플릿 오류에서 오버로드 번호를 볼 수 있습니다. 3 :

template <class... UTypes> 
explicit tuple(UTypes&&... args); 

이 대신 선택됩니다. 왜?

+0

좋아요,'-std = libstdC++'에서는 작동하지 않지만 Clang에서는'-std = libC++'와 함께 작동합니다. 구현 문제 여야합니다. – LogicStuff

+2

gcc의 bugzilla에 버그를 제출하십시오. –

+3

이 질문은 같은 문제가 발생하는 사람들에게 유용한 정보를 제공합니다. 문제는 표준 라이브러리 구현이 아니라 코드에 있음을 알려줍니다. 특정 구현 버그 (MinGW와'stoi' 예를 들어)에 대한 설명 인 많은 일반적인 속임수 타겟이 있습니다. –

답변

3

오버로드 (4), (5)보다 더 가난한 일치가 (3) 통과 할 때 tuple& : (3) 완벽한 전달의 마법을 통해 정확히 일치하는 동안 그들이 const&&& 과부하입니다.

(3)은 Foo(U&&) 생성자가 지나치게 욕심 때문에 유효합니다.

template <class U, 
    std::enable_if_t<std::is_convertible<U,int>{},int>* =nullptr 
> 
Foo(U &&u) : val(std::forward<U>(u)) {} 

를 rvalue 케이스해야하지만, 일을하거나 모호 할 : 그것은 구축에 실패 할 때 일치하지 않도록

Foo(U&&)에 SFINAE 검사를 추가합니다. 실제 예제의 오류 로그를 보면, 볼 수있는 유일한 오류는 lvalue 하나입니다.

+0

와우, 그게 효과가 있습니다! (이것을'typename = std :: enable_if_t :: value>'으로 변경했습니다.) libstdC++와 libC++의 차이점은 무엇입니까? 이것은 구현 세부 사항입니까, 표준에 의해 지정되지 않았습니까? 우리는 그것을 누구에게보고해야 하는가? – LogicStuff

+1

일치하는 문제 :'const auto b'는 여전히 재생산합니다. 이것을 libstdC++에보고해야합니다 (예 : gcc의 bugzilla). 또한 isocpp.org 포럼에서 non-const tuple lvalue를 취하는 생성자를 추가하는 것에 대해 문의하는 것이 좋습니다. 그러면 더 나은 일치입니다. –

+1

@logic 오타 수정에 감사하지만'class ='해결책은'int * = nullptr'보다 나쁩니다. 다중 오버로드의 경우,'class ='는 실패하고,'int * ='는 실패합니다. – Yakk