[英]Type deduction does not work with std::function
我有以下問題。 當我嘗試編譯以下代碼時
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) >
,編譯可以成功完成。
有誰知道我可以如何修正我的代碼,以便我可以簡單地編寫諸如foo<3>( func<float> );
(根據我的第一個代碼示例),而不是
std::function< float(float) > input_func = func<float>;
foo<3>( input_func );
在哪里必須明確聲明input_func
的類型?
提前謝謝了。
這里的問題是,編譯器必須執行重載解析才能找出哪些std::function<U(U)>
實例化具有可以采用T(*)(T)
構造函數。 就是說,可能有多種類型,每種類型可能都有多個input_func
,它們可能占用您的input_func
。
現在,如果看一下Standard,您會發現沒有為std::function
指定這樣的重載,但是所有模板的重載解決規則都是相同的,無論它們來自std::
, boost::
或ACME::
。 編譯器不會開始實例化模板以查找轉換序列。
提供完美匹配后,就無需轉換順序了。 恰好只有一種目標類型不需要轉換序列,編譯器會推斷出這種類型。
在這種特殊情況下,您將了解函數指針與std::function
之間的關系,以及特定的限制,即您必須具有一個返回相同類型(沒有T(*)(U)
)的單一函數,因此您可以增加過載
template< size_t N, typename T >
void foo(T(*func)(T))
{
return foo<N>(std::function<T(T)>(func));
}
類型推論在您的情況下不能正常工作,因為不能推導它。 在大多數情況下,類型推導是與類型和其他模板參數的簡單匹配。 但是,C ++的某些暗角處理一些時髦的規則,但是我不會在此回答。
這是編譯器可以推斷模板參數的示例:
template<typename T>
void test(std::vector<T>);
test(std::vector<int>{1, 2, 3, 4, 5, 6});
這對於編譯器來說很容易。 它需要T
的std::vector
。 您給它一個std::vector
int
。 T
必須是int
。
但是,在您的情況下,發生了很多事情:
template<typename T>
void test(std::function<T(T)>);
int someFunc(int);
test(someFunc);
編譯器無法進行匹配。 自己嘗試:給我一個T
,它將使這兩種類型相等: int(*)(int)
到std::function<T(T)>
。 事實上,有沒有可能T
,可以使這兩個類型是相同的,而矢量版本是一個容易的比賽。
您會對我說:“但是……指向函數的指針可以轉換為std :: function,這很愚蠢!” 是的,確實可以兌換。 但是在進行任何轉換之前,編譯器必須找到T
是什么。 如果沒有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) -> decltype(void(func(std::declval<int>()))) {
// ...
}
在此示例中,將func
限制為可以使用int
調用的func
,並且仍然返回void
。
將func強制轉換為std :: function可明確解決該問題。 例如,下面的代碼有效。
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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.