2

튜플 인 경우 돌보지 않고 입력 인수를 함수에 적용해야하는 경우가 있습니다. 튜플 인 경우 을 풀어야을 언 패킹해야하므로 함수 인수를 검색하지 않아도됩니다. 여기tuple :: tuple 유형에 적용하기 위해 std :: apply를 확장하는 방법은 무엇입니까?

내가 시도 것을 이다 : 그것은 내가 기대했던 인 모호함을 초래

template <typename Callable, typename Tuple> 
auto geniune_apply(Callable&& callable, Tuple&& tuple) 
{ 
    return std::apply(std::forward<Callable>(callable), std::forward<Tuple>(tuple)); 
} 

template <typename Callable, typename T, typename = typename std::enable_if<!shino::is_tuple_like<std::decay_t<T>>::value>::type> 
auto geniune_apply(Callable&& callable, T&& arg) 
{ 
    return std::forward<Callable>(callable)(std::forward<T>(arg)); 
} 

. 그런 다음 튜플 크기에 대한 SFINAE를 시도했지만 비 튜플 유형의 컴파일 오류를 방지 할 수는 없었습니다. 여기

테스트 케이스 내가 사용하고 있습니다 : 튜플 같은, 필요한 경우에 대한

#include <cassert> 
#include <iostream> 
#include <stdexcept> 
#include <vector> 

int dummy_x(const std::tuple<int, int>&) 
{ 
    return 1; 
} 

int dummy_y(int y) 
{ 
    return y; 
} 

int main() 
{ 
    shino::geniune_apply(&dummy_x, std::tuple<int, int>(1, 1)); 
    shino::geniune_apply(dummy_y, 1); 
    shino::geniune_apply(dummy_y, std::make_tuple(1)); 
} 

코드입니다.

template <typename Callable, typename Arg> 
decltype(auto) geniune_apply(Callable&& callable, Arg&& arg) 
{ 
    return details::genuine_apply(std::forward<Callable>(callable), 
     std::forward<Arg>(arg), 
     is_tuple_like<std::decay_t<Arg>>{}); 
} 

가 상속하기 위해 is_tuple_like 변경 :

template <typename T> 
    struct is_straight_tuple 
    { 
     static constexpr bool value = false; 

     constexpr operator bool() 
     { 
      return value; 
     } 
    }; 

    template <typename ... Ts> 
    struct is_straight_tuple<std::tuple<Ts...>> 
    { 
     static constexpr bool value = true; 

     constexpr operator bool() 
     { 
      return value; 
     } 
    }; 

    template <typename T> 
    struct is_std_array 
    { 
     static constexpr bool value = false; 
    }; 

    template <typename T, std::size_t size> 
    struct is_std_array<std::array<T, size>> 
    { 
     static constexpr bool value = true; 

     constexpr operator bool() 
     { 
      return value; 
     } 
    }; 

    template <typename T> 
    struct is_tuple_like 
    { 
     static constexpr bool value = is_std_array<T>::value || is_straight_tuple<T>::value; 

     constexpr operator bool() 
     { 
      return value; 
     } 
    }; 
+0

std :: apply는 C++ 17이지만 constexpr 인 경우 활성화하는 방법을 모르므로 C++ 14로 태그를 지정하기로 결정했습니다. – Incomputable

답변

2

가장 간단한 방법은 C++ 14입니다 그냥 태그 파견을 사용하려면이을의 해결 :이 std::array 또는 std::tuple 경우 그것은 기본적으로 테스트 std::integral_constant<bool, ???>을 다시 구현하는 대신 이는 다음 두 가지 도우미 함수를 작성 할 수 있습니다 것입니다 :

namespace details { 
    // the tuple-like case 
    template <typename Callable, typename Tuple> 
    decltype(auto) genuine_apply(Callable&&, Tuple&&, std::true_type); 

    // the non-tuple-like case 
    template <typename Callable, typename Arg> 
    decltype(auto) genuine_apply(Callable&&, Arg&&, std::false_type); 
} 

C++ (17), 길 더 좋은 솔루션은 단순히 대신 태그 파견의 if constexpr을 사용하는 것입니다에서. C++ 개념을 사용하면 문제에 대한 초기 접근 방식은 실제로 그대로 작동합니다 (하나의 제한되지 않은 함수 템플릿을 가지며 튜플과 같은 두 번째 인수에 제약을받는).