2016-10-17 8 views
2

私は以下の問題があります。私は次のコードタイプ控除が機能しません

template< typename T > 
T func(T t) 
{ 
    return t; 
} 

template< size_t N, typename T > 
void foo(std::function< T(T) > func) 
{ 
    // ... 
} 

int main() 
{ 
    foo<3>(func<float>); 

    return 0; 
} 

をコンパイルしようとすると、私はエラーを取得する:

no matching function for call to 'foo' 
     foo<3>(func<float>); 
     ^~~~~~ 
/Users/arirasch/WWU/dev/xcode/tests/tests/main.cpp:18:10: note: candidate template ignored: could not match 'function<type-parameter-0-1 (type-parameter-0-1)>' against 'float (*)(float)' 
    void foo(std::function< T(T) > func) 

しかし、私は

template< typename T > 
T func(T t) 
{ 
    return t; 
} 

template< size_t N, typename T > 
void foo(std::function< T(T) > func) 
{ 
    // ... 
} 

int main() 
{ 

    std::function< float(float) > input_func = func<float>; 
    foo<3>(input_func); 

    return 0; 
} 

つまり、私はの入力関数を宣言するときに、それを修正するときfooを明示的にstd::function< float(float) >と指定すると、正常にコンパイルできます。

誰もが私は単に代わりinput_funcの種類を明示的に指定する必要があります

std::function< float(float) > input_func = func<float>; 
foo<3>(input_func); 

の(私の最初のコード例に係る)foo<3>(func<float>);ような何かを書くことができるように、私が代わりに私のコードをFIXEことを知っていますか?

事前に感謝します。

+1

機能を 'のstd :: function'sではありません。 –

答えて

3

推論できないため、あなたのケースではタイプ控除が機能しません。型控除は、ほとんどの場合、型やその他のテンプレートパラメータとの単純な一致です。しかし、C++のダークコーナーにはファンキーなルールがある控除を扱っていますが、私はこの答えにはつきません。

これは、コンパイラがテンプレート引数を推測することができます例です。

template<typename T> 
void test(std::vector<T>); 

test(std::vector<int>{1, 2, 3, 4, 5, 6}); 

これは、コンパイラのために簡単です。 Tのベクトルが必要です。整数のベクトルを与えます。 Tはintでなければなりません。

template<typename T> 
void test(std::function<T(T)>); 

int someFunc(int); 

test(someFunc); 

コンパイラが一致することはできません。

しかし、あなたの場合には、起こって多くのものがあります。あなた自身のために試してみてください:私にこれらの2つのタイプを等しくするTを与えてください:int(*)(int)からstd::function<T(T)>。確かに、これら2つのタイプを同じにすることはできませんTはありませんが、ベクターバージョンは簡単に一致しました。

あなたは私に言うでしょう: "しかし...関数へのポインタは、std :: functionに変換可能です。あなたは愚かです!"ええ、それは本当にコンバーチブルです。しかし、変換の前に、コンパイラはを見つけるためにを持っています。 Tがなければ、関数へのポインタからどのクラスに変換するのですか?多くのクラス? Tに一致するようにしてください。あなたの機能がコンバーチブルになる可能性は複数あります。


どうすればこの作品を制作できますか? std::functionは忘れてください。ちょうどTを受け取ります。

template<typename T> 
T func(T t) { 
    return t; 
} 

template<size_t N, typename T> 
void foo(T func) { 
    // ... 
} 

int main() 
{ 
    foo<3>(func<float>); 

    return 0; 
} 

この例はどのようにうまく機能しているかに注目してください。あなたは変換がありません。std::functionというものはありません。あなたが想像することのできる呼び出し可能なもので動作します!

どのようなタイプの受け入れが心配ですか?ここで心配する必要はありません!パラメータ型は、テンプレートが受け取ったパラメータで何ができるのかを表現するのに悪い方法です。 で制限する必要があります。その表現は、あなたがTをどのように使うべきか、そしてどのインタフェースTが必要であるかを他人に伝えます。ところで、私たちはそのsfinaeを呼び出します。この例では

template<size_t N, typename T> 
auto foo(T func) -> void_t<decltype(func(std::declval<int>()))> { 
    // ... 
} 

、あなたはintで呼び出し可能であることをfuncを制限します。

あなたはまだC++ 17コンパイラを持っていない場合、あなたはこのようなvoid_t実装できます

template<typename...> 
using void_t = void; 
+0

"タイプ控除は単純なマッチです..."まあ、いいえ。それが起こっている場所の一覧を見て、コンテキストがどのようなものであるかを見てみましょう。 C++言語の証ですが、それは簡単ですね。 – MSalters

+0

真。私は私の答えを編集します。指摘してくれてありがとう。 –

4

ここで問題となるのは、std::function<U(U)>インスタンシエーションのコンストラクタがT(*)(T)であることを確認するために、コンパイラがオーバーロード解決を行う必要があることです。つまり、複数のタイプがあり、それぞれがあなたのinput_funcを取ることができる複数のctorsを持つ可能性があります。

今、あなたは標準を見れば、あなたはstd::functionのために指定されたそのような過負荷が存在しないことがわかりますが、オーバーロード解決規則は、彼らがしているかどうか、すべてのテンプレートで同じですstd::boost::またはACME::から。コンパイラは、変換シーケンスを見つけるためにテンプレートのインスタンスを作成しません。

完全一致を指定すると、変換シーケンスは不要です。厳密に1つのターゲットタイプがあり、変換シーケンスは必要なく、コンパイラはこのタイプを推論します。

この特定のケースでは、あなたが関数ポインタとstd::functionとの関係について知っている、ともあなたが同じタイプ(なしT(*)(U))を返す単一の機能を持っている必要がありますので、過負荷

を追加することができ、特定の制限について
template< size_t N, typename T > 
void foo(T(*func)(T)) 
{ 
    return foo<N>(std::function<T(T)>(func)); 
} 
2

関数funcをstd ::関数にキャストすると、明示的に問題が解決されます。例えば。以下のコードは動作します。

template< typename T > 
T func(T t) 
{ 
    return t; 
} 

template<typename T> 
using FuncType = std::function<T(T)>; 

template< size_t N, typename T > 
void foo(FuncType<T> func) 
{ 
    // ... 
} 

int main() 
{ 
    func<float>(1.0); 
    foo<3>(FuncType<float>(func<float>)); 

    return 0; 
} 
関連する問題