2

タプルであるかどうかを気にせずに入力引数を関数に適用する必要がある場合があります。タプルの場合は、を展開する必要があります。したがって、関数の引数の検出は不要です。ここで非タプル型の作業に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::arraystd::tupleであればそれは基本的にテストstd::integral_constant<bool, ???>を再実装する代わりに。これは、これら2つのヘルパー関数を書くことができます:

C++ 17では
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); 
} 

、よりよい解決策は、単にタグディスパッチの代わりにif constexprを使用することである方法。 C++のコンセプトでは、問題への最初のアプローチは実際にはそのままの状態になります(制約のない関数テンプレートが1つあり、第2引数にタプルのような制約があります)。

関連する問題