2017-01-15 10 views
6

내 코드에서 가독성을 높이기 위해 std::get이라는 별칭을 사용해야합니다.std 템플릿 함수의 앨리어싱

불행히도 컴파일 타임 오류 get<0> in namespace ‘std’ does not name a type이 있습니다. usingtypedef과 동일하므로 작업 할 수있는 유형이 필요합니다. 나는 몇 가지 데이터 유형 표현하기 위해 std::tuple을 사용하고 있습니다 :

using myFoo = std::tuple<int,int,double,string>; 
using getNumber = std::get<0>; 

좀 이전 질문보고를하지만, 제안 된 솔루션은 포장 및 std::forward을 사용하는 것입니다. 각 멤버에 대해 이러한 코드를 작성하고 싶지 않습니다.

키워드를 사용하는 경우에만 를 사용하여이 문제를 해결 얻을 수있는 방법이 있나요 ?

+5

"_using 키워드 만 사용하여이 문제를 해결할 수있는 방법은 무엇입니까?" No. – cpplearner

+0

'C++ 11','C++ 14','C++ 1z'를 동시에 사용할 수 없습니다. – Inline

+0

이 변경 사항보다 제안이 있습니까? –

답변

9

키워드 만 사용하면이 문제를 해결할 수있는 방법이 있습니까?

내가 std::get이 형이 아닌 대한, 아니을 말할 것이다 (따라서이 같은 사용 대상에서 제외입니다).
또한 가능한 경우에도 std::get은 오버로드 된 함수이므로 사용자가 특정 구현에 바인딩해야합니다. C++ 17 말했다

, 당신은 같은 것을 할 수 있습니다

#include<tuple> 
#include<utility> 

using myFoo = std::tuple<int,int,double>; 
constexpr auto getNumber = [](auto &&t) constexpr -> decltype(auto) { return std::get<0>(std::forward<decltype(t)>(t)); }; 

template<int> struct S {}; 

int main() { 
    constexpr myFoo t{0,0,0.}; 
    S<getNumber(t)> s{}; 
    (void)s; 
} 

당신이 볼 수 있듯이, constexpr 람다 변수는 컴파일 시간을 만드는 데 도움이 래퍼 (나 가정 해 봅시다) 함수의 이름을 바꿀 수 있습니다.


정확하게 @ T.C에서 지적한 바와 같이. 그것은 다음과 같이

template<int N> 
constexpr auto getFromPosition = [](auto &&t) constexpr -> decltype(auto) { return std::get<N>(std::forward<decltype(t)>(t)); }; 

지금 당신이 그것을 호출 할 수 있습니다 :

S<getFromPosition<0>(t)> s{}; 
당신이 더 그것을 일반화 std::get에 대한 거의 완벽한 별명을 얻으려면 코멘트에, 당신은 변수 템플릿을 사용할 수 있습니다

wandbox에서 확인하십시오.

+3

우리는 어떤 종류의 람다가 지배하는 낙원에 있습니까? 평범한 구식 기능을 방해 한 것은 무엇입니까? –

+0

이것은 일반적인 람다입니다. 템플릿 기능은 –

+0

@ n.m과 마찬가지로 작동합니다. C++ 17은 어떻게 든 흥미 롭습니다. :-) – skypjack

4

당신은 그것을 할 수있는 using + enum :

#include<tuple> 

using myFoo = std::tuple<int,int,double>; 

int main() { 
    constexpr myFoo t{0,0,0.}; 
    enum { Number = 0 }; 
    using std::get; 

    auto&& x = get<Number>(t); 
    (void)x; 
} 

동시에 열거하고 튜플을 유지해야하기 때문에 불행하게도,이 DRY 아니지만.

필자가 생각하기에, 이것을 달성하는 가장 건조하고 가장 안전한 방법은 튜플에 태그 값을 사용하는 것이다. 각 태그 유형 중 최대 하나까지 튜플을 제한하십시오.

#include <tuple> 
#include <iostream> 

// 
// simple example of a tagged value class 
// 
template<class Type, class Tag> 
struct tagged 
{ 
    constexpr tagged(Type t) 
     : value_(t) {} 

    operator Type&() { return value_; } 

    operator Type const&() const { return value_; } 

    Type value_; 
}; 

struct age_tag {}; 
struct weight_tag {}; 
struct height_tag {}; 

using Age = tagged<int, age_tag>; 
using Weight = tagged<int, weight_tag>; 
using Height = tagged<double, height_tag>; 

int main() 
{ 
    constexpr auto foo1 = std::make_tuple(Age(21), Weight(150), Height(165.5)); 
    constexpr auto foo2 = std::make_tuple(Weight(150), Height(165.5), Age(21)); 
    using std::get; 

    // 
    // note below how order now makes no difference 
    // 

    std::cout << get<Age>(foo1) << std::endl; 
    std::cout << get<Weight>(foo1) << std::endl; 
    std::cout << get<Height>(foo1) << std::endl; 

    std::cout << "\n"; 

    std::cout << get<Age>(foo2) << std::endl; 
    std::cout << get<Weight>(foo2) << std::endl; 
    std::cout << get<Height>(foo2) << std::endl; 
} 

예상 출력 : 일반적으로

21 
150 
165.5 

21 
150 
165.5 
+0

'' 구조체 S {}; '템플릿을 삭제해야 하나 생각 했나요? –

+0

@chedynajjar 아 그래, 난 skypjack의 대답을 침대로했다. –

+0

@chedynajjar 두 번째 접근 방식이 이제 DRY –

1

, tuple은 일반적인 코드에 사용되어야한다

태그는 기본적으로 몇 가지 독특한 개념 니모닉입니다.

필드 1이 숫자 또는 치킨 인 경우, tuple을 사용하면 안됩니다. 에 Number이라는 입력란을 사용해야합니다. 당신이 (하나처럼) 튜플과 같은 기능이 필요한 경우

, 당신은 단순히 as_tie을 작성할 수 있습니다

struct SomeType { 
    int Number; 
    std::string Chicken; 

    auto as_tie() { return std::tie(Number, Chicken); } 
    auto as_tie() const { return std::tie(Number, Chicken); } 
}; 

지금 당신이 someInstance.as_tie()를 입력하여 참조의 tupleSomeType에 액세스 할 수 있습니다.

이것은 여전히 ​​무료로 < 또는 == 등을주지는 못합니다. 우리는 한 장소에서 그렇게하고 as_tie 기술을 사용하는 모든 곳을 다시 사용할 수 있습니다 : 우리를 제공

struct as_tie_ordering { 
    template<class T> 
    using enable = std::enable_if_t< std::is_base_of<as_tie_ordering, std::decay_t<T>>, int>; 

    template<class T, enable<T> =0> 
    friend bool operator==(T const& lhs, T const& rhs) { 
    return lhs.as_tie() == rhs.as_tie(); 
    } 
    template<class T, enable<T> =0> 
    friend bool operator!=(T const& lhs, T const& rhs) { 
    return lhs.as_tie() != rhs.as_tie(); 
    } 
    template<class T, enable<T> =0> 
    friend bool operator<(T const& lhs, T const& rhs) { 
    return lhs.as_tie() < rhs.as_tie(); 
    } 
    template<class T, enable<T> =0> 
    friend bool operator<=(T const& lhs, T const& rhs) { 
    return lhs.as_tie() <= rhs.as_tie(); 
    } 
    template<class T, enable<T> =0> 
    friend bool operator>=(T const& lhs, T const& rhs) { 
    return lhs.as_tie() >= rhs.as_tie(); 
    } 
    template<class T, enable<T> =0> 
    friend bool operator>(T const& lhs, T const& rhs) { 
    return lhs.as_tie() > rhs.as_tie(); 
    } 
}; 

:

struct SomeType:as_tie_ordering { 
    int Number; 
    std::string Chicken; 

    auto as_tie() { return std::tie(Number, Chicken); } 
    auto as_tie() const { return std::tie(Number, Chicken); } 
}; 

지금

SomeTime a,b; 
bool same = (a==b); 

작품. as_tie_ordering은 CRTP를 사용하지 않으며 비어있는 상태 비 저장 클래스입니다. 이 기술은 Koenig lookup을 사용하여 인스턴스에서 연산자를 찾을 수있게합니다. 또한 구현할 수

가 작동 std::tuple_size 얻기 get

struct as_tie_get { 
    template<class T> 
    using enable = std::enable_if_t< std::is_base_of<as_tie_get, std::decay_t<T>>, int>; 

    template<std::size_t I, class T, 
    enable<T> =0 
    > 
    friend decltype(auto) get(T&& t) { 
    using std::get; 
    return get<I>(std::forward<T>(t).as_tie()); 
    } 
}; 

을 ADL 기반은 슬프게도, 쉽지 않다.

위의 enable<T> =0 절은 MSVC에서 class=enable<T>으로 대체해야합니다. 컴파일러는 C++ 11을 준수하지 않기 때문입니다.

내가 위에 언급 한 내용은 tuple입니다. 하지만 일반적으로 을 사용하고 있습니다. 내 타입을 튜플로 변환 한 다음 튜플의 <을 사용하여 <을 작성한다. 그 글루 코드는 묶음을 일반적인 유형의 묶음으로 취급합니다. 그것이 tuple을위한 것입니다.

+0

'use_tie_for_operations'는 무엇입니까? –

+0

@ T.C. '=='연산을 ADL 룩업 영역으로 가져 와서 필요한 클래스 당 한 줄의 코드로'==','! =','<', '<=', '> ='및'>'을 자동으로 구현하는 클래스입니다 대체 우주에서 타입을 'as_tie_ordering'으로 바꿨습니다. – Yakk