2016-08-10 12 views
0

C++でテンプレートを使用していくつかの魔法を実行しています。特定の戻り値の型を持つ関数型をとるC++テンプレート関数

このケースでは、Listタイプとデータを含むListElementタイプのナイーブな汎用リスト実装を作成しました。

私はすでに任意の引数リストを持つリストに格納された型の任意のメンバ関数型をとり、指定されたリスト内の各要素に対してそのメンバ関数を呼び出す引数:

問題は、呼び出された関数の戻り値に「反応」できないことです。私は.map機能を実装したくはありませんが!

今、コールが "true"を返してから停止するまで、リスト内の値に対して関数を呼び出す "for each call until"を実装したいと思います。そのためには、テンプレートパラメータとして挿入された関数を、ブール値を返す任意の型の関数に限定する必要があります。私は、コンパイラが文句を停止するまでの周りに型指定されたと、この得た:ここで何が起こっている

template<bool (*function), typename ... arguments> 
void for_each_call_until(arguments ... args) 
{ 
    for(ListElement * current = this->first; current != nullptr; current = current->next) 
    { 
     if((current->value->*function)(args ...)) break; 
    } 
} 

、これは正しい方法で、そうでない場合、正しい方法は何ですか?

EDIT:std :: namespaceの関数を使用することをお勧めする人もいます。これらの小さなトレーニングセッションでは、stdを避けようとしています:: std ::を使用したいと思うようなペストすべての

#include <type_traits> 
#include <utility> 

template<typename T> struct is_bool; 

template<> struct is_bool<bool> { typedef int value; }; 

template<typename function, typename ... arguments> 
void for_each_call(function call, arguments && ... args) 
{ 
    typedef decltype(call(std::forward<arguments>(args)...)) ret_type; 

    typedef typename is_bool<ret_type>::value x; 

    call(std::forward<arguments>(args)...); 
} 

bool foo(int, int) {} // Compiles 

// int foo(int, int) {} // Does not compile 

int main() 
{ 
    for_each_call(foo, 4, 2); 
    return 0; 
} 
+0

ないソリューションが、迅速かつ汚いです(current-> value-> * call)(args)の戻り値をbooleanローカル変数に代入することです。関数が実際にブール値を返さない限り、この代入はコンパイルに失敗します。したがって、実際にはブール値を返す関数だけを受け入れるように関数を制限します。私が正しく思い出すと、結果のコンパイルエラーは実際にはかなり有益です。「<間違った戻り値の型>をブール値に変換できません。 –

+0

この方法は、関数がintを返す場合にも機能しますが、これは間違っています。 –

+0

さて、私たちはC++について、Boolの背後にあるセマンティクスと戻り値の型としてintを考えています。 – salbeira

答えて

-1

簡単な解決策は、コンパイル・エラーを強制的に部分的な特殊化を使用することを含むようなもののこれらの小さなstandardimplementationsアプローチは不必要に限定的である:

(current->value->*call)(args ...); 

にはメンバー関数が必要な場合は、実際にできる操作はほんの少しです。通話者がもっとやりたいのであれば、彼らは一種のものです。代わりに、一般化して最初の引数としてcurrent->valueを渡しますが、今あなたも呼び出し可能の任意の種類を渡すことができます - - ではなく、あなたがstd::mem_fn(&Class::mem)を渡す前に、あなたは&Class::memを通過する

template<typename function, typename ... arguments> 
void for_each_call(function call, arguments ... args) 
{ 
    for(ListElement * current = this->first; current != nullptr; current = current->next) 
    { 
     call(current->value, args...); 
    } 
} 

これは、すべてのケースの前などに取り組んでいます。


あなたの主な質問にしてください。違うことをする必要はありません。 call()の結果を使用してください:

template<typename function, typename ... arguments> 
void for_each_call(function call, arguments ... args) 
{ 
    for(ListElement* current = this->first; current != nullptr; current = current->next) 
    { 
     if (call(current->value, args...)) { 
      break; 
     } 
    } 
} 

それだけです。文脈上にboolに変換可能なものを返さない呼び出し可能コードをユーザーが提供すると、コンパイルエラーが発生します。なぜboolを返すだけに制限されますか?

あなたが本当に必要な場合だけbool、静的アサートを投げる:

template<typename function, typename ... arguments> 
void for_each_call(function call, arguments ... args) 
{ 
    static_assert(std::is_same<decltype(call(this->first->value, args...)), bool>::value, "Must be bool!"); 
    // rest... 
} 

注:あなたは、おそらくコピーの多くを回避するために、constを参照することにより、あなたのarguments...を取りたいです。

1

まず、これを:リスト、ベクトルまたはマッピング自身が、使用するのstd ::または後押し::

+0

私が考えた最初のアプローチでしたが、エラー:>>。* << or >> - > * <<は、呼び出し(...)<< , eg. >(... - > * call)(...で関数として要素へのポインタを呼び出すために使用する必要があります。 )。<<。それが私がメンバー機能に限定した理由です。 – salbeira

+0

@salbeiraあなたが何を言っているのか分かりません。 ['mem_fn()'](http://en.cppreference.com/w/cpp/utility/functional/mem_fn)を使いましたか? – Barry

+0

いつ、どこに?私のトレーニングセッションでは、私はstd ::を使用すると私は個人的な成功のこれらの小さなスニペットを書く必要はないので、とpropablyに私は標準を避けるためではありません: - P – salbeira

0

だけメンバ関数ポインタはをどのように動作するかをお見せするために、この最低料金:

class Foo { 
public: 
    bool test() { return true; } 
}; 

/// The function takes a member function of a class T and its arguments. 
template<typename T, typename... Args> 
void for_each_call_until(bool (T::*member_function)(Args...), 
         Args&& ... args) { 
    T obj; // Instantiate an example object. 
    bool rts = (obj.*member_function)(std::forward<Args>(args)...); 
    if (rts == false) { // Check for the result of the member function 
    // close 
    } 
    // ... 
} 

あなたの機能のようなものが考えられます。本当に

template<typename... Args> 
void for_each_call_until(bool (ListElement::*member_function)(Args...), 
         Args&& ... args) { 
    for (/* iteration over pointers */) { 
    bool rts = (current->*member_function)(std::forward<Args>(args)...); 
    if (rts == false) { 
     // break 
    } 
    // ... 
} 
}