3

次のテンプレート関数があります。

template <typename...Args, typename Func>
void call(const char *name, Args...args, Func f)
{
        f(3);
}

私がそれを使用しようとすると、

    call("test", 1, 2, 3, [=](int i) { std::cout<< i; });

コンパイラは、テンプレート引数を推測できないと文句を言いますFuncargs関数ポインター以外の任意の型である可能性があることを知って、この問題をどのように解決できますか。

4

3 に答える 3

8

14.1p11 から:

関数テンプレートのテンプレート パラメーター パックは、そのテンプレート パラメーターが関数テンプレートのパラメーター タイプ リストから推定できるか、または既定の引数 (14.8.2) を持っていない限り、別のテンプレート パラメーターを続けてはなりません。

callable を最後の引数として保持したい場合は、次を使用できますforward_as_tuple

template <typename...Args, typename Func>
void call(const char *name, std::tuple<Args...> args, Func f)
{
        f(3);
}

call("test", std::forward_as_tuple(1, 2, 3), [=](int i) { std::cout<< i; });

tuplecallable を含むように を合成することで、実際にはより良い結果が得られます。

#include <tuple>

template<typename... Args_F>
void call_impl(const char *name, std::tuple<Args_F... &&> args_f) {
   auto &&f = std::get<sizeof...(Args_F) - 1>(args_f);
   f(3);
}

template<typename...ArgsF>
void call(const char *name, ArgsF &&...args_f) {
   call_impl(name, std::tuple<ArgsF &&...>(std::forward<ArgsF>(args_f)...));
}
于 2013-04-12T17:54:54.483 に答える
4

get_lastパラメータ パックの最後の要素を抽出するWrite 。

それを呼び出しますf。コールしfます。

例として、

template<typename T0>
auto get_last( T0&& t0 )->decltype(std::forward<T0>(t0))
{
  return std::forward<T0>(t0);
}
template<typename T0, typename... Ts>
auto get_last( T0&& t0, Ts&&... ts )->decltype(get_last(std::forward<Ts>(ts)...))
{
  return get_last(std::forward<Ts>(ts)...);
}

オーバーロードの解決を気にしない場合はget_last、ファンクターのように呼び出して処理するだけで十分かもしれません。

template <typename...Args>
void call(const char *name, Args...&& args)
{
    auto&& f = get_last(std::forward<Args>(args)...);
    f(3);
}

次のステップは、有効なファンクターを最後に渡さない場合に一致しないようにするために、いくつかの SFINAEenable_ifマジックを実行することです。ただし、これはおそらくやり過ぎです。call

が機能するかどうかを検出するにf(3)は、単純な特性クラスを使用します。

// trivial traits class:
template<typename T>
struct is_type:std::true_type {};

template<typename Functor, typename=void>
struct can_be_called_with_3:std::false_type {}

template<typename Functor>
struct can_be_called_with_3<Functor,
  typename std::enable_if<
    std::is_type< decltype(
      std::declval<Functor>(3)
    ) >::value
  >::type
>:std::true_type {}

これはかなりばかげています。渡された型の要件がより複雑な場合 (たとえば、引数を指定して呼び出す必要がある場合) は、より洗練された traits クラスを使用する必要があります。

次に、次のように拡張callします。

template <typename...Args>
auto call(const char *name, Args...&& args)
  -> typename std::enable_if<
       can_be_called_with_3< decltype( get_last(std::forward<Args>(args)... ) ) >::value
     >::type
{ /* body unchanged */ }

これはかなり鈍いです。

于 2013-04-12T17:50:07.663 に答える
0

引数のパックをテンプレートとして使用したい場合、既に行った方法でこれを書くことはできません:

template <typename...Args, typename Func>
void call(const char *name, Args...args, Func f)
{
        f(3);
}

ただし、それらを次のようにパックできますstd::tuple

template <typename...Args, typename Func>
void call(const char *name, std::tuple<Args...> args, Func f)
{
        f(3);
}

call("test", std::forward_as_tuple(1, 2, 3), [=](int i) { std::cout<< i; });
于 2013-04-12T18:03:24.260 に答える