2012-04-25 12 views
2
// some arbitrary function 
template<typename T> 
void log(T&& obj) 
{ 
    std::cout << obj << std::endl;  
} 

// arbitrary transformation 
template<typename T> 
T convert(T&& obj) { 
    return obj; 
} 

template<template <typename> typename F, typename... T> 
void callOn(F<T> func, /// issue: what's the type of func?     
      T&&... params) 
{ 
    func(std::forward<T>(convert(std::forward<T>(params)))...); 
} 

int main() 
{ 
    callOn(log, -1, -2.0);  
    return 0; 
} 

これはまったく可能ですか?テンプレートテンプレート関数の可変パラメータを展開しますか?

コンパイラが「callOn(、.. ..」)の呼び出しに一致する関数がありません。どうして ?

更新:仮定するログは

template<typename T> 
void log(T&& value) { std::cout << value << std::endl; } 

template<typename First, typename... Rest> 
void log(First&& f, Rest&&... rest) 
{ 
    std::cout << f << ","; 
    log(std::forward<Rest>(rest)...); 
} 

単項関数ではありませんcallOnは、ログの種類が一致しない「テンプレート」と入力取りますか? funcの種類を指定するには?

+2

メタメタプログラミングですか?私たちはもっと深く行かなければなりません! –

+0

野生の推測: 'template typename F'を試してみましたか? – Philipp

+0

@Philipp:これも私の考えでしたが、 'callOn(log、-1、-2.0);'は 'log'に2つの引数を渡そうとします。これは単項式です。 – ildjarn

答えて

2

関数オブジェクトを使用します。ここでは、コンパイルの例です:

#include <utility> 
#include <iostream> 

struct Log 
{ 
    template<typename T> void operator()(T&& t) { 
     std::cout << t << std::endl; 
    } 

    template<typename T, typename... Rest> void operator()(T&& t, Rest&&... rest) 
    { 
     std::cout << t << ", "; 
     (*this)(std::forward<Rest>(rest)...); 
    } 
}; 

template<typename T> 
T convert(T&& obj) { 
    return obj; 
} 

template<typename F, typename... T> 
void callOn(F funcobj, T&&... params) 
{ 
    funcobj(std::forward<T>(convert(std::forward<T>(params)))...); 
} 

int main() 
{ 
    callOn(Log(), -1, -2.17, "abc"); 
    return 0; 
} 
+0

'std :: forward'(' convert'への呼び出しをラッピングする)の内部は必要ではなく、 'convert'のいくつかのオーバーロードが特別なことを行うことを意図している場合、おそらく干渉します。 –

1

私はtemplate <typename> typename Fの構文が正しいとは思わない、とStandardは、テンプレートテンプレートパラメータのテンプレート引数は名前のものでなければならない」という14.3.3/1で指定しましたクラステンプレートまたはエイリアステンプレート "であり、関数テンプレートではありません。あなたは関数テンプレートを渡したい場合は、関数へのポインタなどのパラメータを宣言することができます。

template<typename... T> 
void callOn(void (*func)(T&&...params), 
      T&&... params) 
{ 
    //same as before 
} 

そしてcallOn(log, -1, -2.0);が呼び出されたときに、Tのタイプはlogからではなく、{-1、-2.0から推定されていません}を{int、double}とすると、funclog<int, double>(int&&, double&&)を指すポインタから初期化されます。

+0

関数ポインタをstd ::関数として表現できますか? –

+0

void(* func)(T && ...)は機能しますが、std :: function funcは機能しません。コンパイラは、 'std :: function 型への変換に基づいて、オーバーロードされた関数'ログ 'を解決できないと訴えます。 –

+0

'template typename F'は正しくありませんあなたの理論的根拠は間違っています - 'template class F'は本当に有効です。関数テンプレートではなくテンプレートファンクタを使うだけです。 – ildjarn

関連する問題