簡體   English   中英

傳遞具有模板化返回類型的std :: function類型

[英]Passing std::function type which has a templated return type

我有一個功能

template<typename P = int_fast16_t, typename I>
std::vector<std::vector<P>> f(
    I xb, I xe, I yb, I ye,
    std::function<P(typename std::iterator_traits<I>::value_type,
                    typename std::iterator_traits<I>::value_type)> &&score_function,
    P ID = -1, P S = -1, P M = 1)

它需要兩對迭代器和一個函數,它應該比較迭代器的value_type的兩個元素,並返回一個類型為P的值。

這給了我一個錯誤

./h.hpp:47:32: note: candidate template ignored: could not match 'function<type-parameter-0-0 (typename iterator_traits<type-parameter-0-1>::value_type, typename iterator_traits<type-parameter-0-1>::value_type)>' against 'stringAlgorithms::scoring::plus_minus_one'
   std::vector<std::vector<P>> nw_score_matrix(I xb, I xe, I yb, I ye, 

現在,如果我將其更改為使用特定的返回類型P.

template<typename P = int_fast16_t, typename I>
   std::vector<std::vector<P>> nw_score_matrix(I xb, I xe, I yb, I ye, std::function<int_fast16_t(typename std::iterator_traits<I>::value_type, typename std::iterator_traits<I>::value_type)> &&score_function, P ID = -1, P S = -1, P M = 1)

這個編譯。

在這種情況下,函數plus_minus_one是

  struct plus_minus_one {
     template<typename T, typename R = int_fast16_t>
     R operator()(const T &x, const T &y) { return x == y ? 1 : -1; }
  };

並通過使用

scoring::plus_minus_one matchScoring;

nw_score_matrix(x.begin(), x.end(), y.begin(), y.end(), matchScoring);

我意識到我可以在模板中聲明一個typename F並使score_function成為a

F &&score_function

但是我想確保如果有人創建了一個特定於某些類型的functor / lambda,那么該函數會處理正確的類型。 那么為什么聲明不能編譯?

編輯:找到一個完整的例子https://github.com/meconlen/stringAlgorithms/tree/soq

要調用該函數,您需要實際給它一個std::function

scoring::plus_minus_one matchScoring;
std::function<int_fast16_t(int,int)> score_function = matchScoring;
nw_score_matrix(x.begin(), x.end(), y.begin(), y.end(), std::move(score_function));

否則,編譯器的轉換次數太多,無法確定您要執行的操作。

簡要說明。 當你寫:

template <typename P = int>
void f(std::function<P()>) {}

然后P仍處於推導的上下文中,這意味着編譯器將嘗試根據參數表達式的類型推導出P ,忽略默認值( int )。 但是,類型推導僅推導出類型,即參數表達式的類型必須與相應參數的類型匹配,以便編譯器推導出缺少的類型模板參數。

所以,一旦你調用如下函數:

std::function<float()> a;
f(a);

編譯器將用float替換P

現在,如果你想傳入一個函數的地址:

char foo() { return {}; }
f(&foo);

編譯器會抱怨它不能推斷出P ,因為:

  1. 它仍處於推斷的背景中。
  2. 參數的類型( char(*)() )與參數std::function<P()>的類型不匹配。

即,編譯器不知道P從一個簽名std::function<P()>應當克服復位類型的函數指針,匹配char

比方說,您可以明確強制類型:

f<char>(&foo);

但那不是很靈活。

您還可以將std::function放在非推導的上下文中,並在其他地方推導出P

template <typename T> struct identity { using type = T; };

template <typename P>
void f(typename identity<std::function<P()>>::type, P c) {}

f(&foo, 'a'); // P will be deduced from the 'a' argument

但是如果c是默認的並且未在函數調用參數列表中指定,則這將不起作用。

沒有什么可以阻止你推斷出參數表達式的確切類型:

template <typename F>
void f(F&& f) {}

f(&foo);

如果您在意,您可以隨時檢查f返回的是否可轉換為P ,或者只讀取該類型。

在您的場景中,完全不相關類型的實例( plus_minus_one )作為std::function的實例傳遞,因此顯然,推斷失敗。 編譯器不知道它必須查看其operator() ,並使用其默認的返回類型。

std::function本身是一個類型擦除器,在你的情況下你真的不需要擦除任何類型。

使用Piotr Skotnicki提供的建議,我為您獲得了以下可能的解決方案。 您希望C ++推斷出score_function本身的類型,而不是它的嵌套類型。 但是,一旦你有這種類型 - 讓我們稱之為F ,那么你可以手動檢索你需要的東西。

這個輔助特征結構提取P從給定功能類型代碼F (這基本上彼得Skitnicki的評論)

template<typename F, typename I>
struct PP {
    typedef typename std::decay<typename std::result_of<
      F(typename std::iterator_traits<I>::value_type,
        typename std::iterator_traits<I>::value_type)
      >::type>::type type;
};

現在,有了這個幫助,您可以將您的功能定義為:

template<typename I, typename F>
   std::vector<std::vector<typename PP<F,I>::type>>
     nw_score_matrix(I xb, I xe, I yb, I ye,
                     F &&score_function,
                     typename PP<F,I>::type ID = -1,
                     typename PP<F,I>::type S = -1,
                     typename PP<F,I>::type M = 1)
   {
       typedef typename PP<F,I>::type P;

       ....... your existing code ......
   }

...然后您可以在呼叫站點上調用該功能而無需任何更改。 特別是,您不需要將matchScoring轉換為std::function對象。

我相信它符合你的要求F可能是一個仿函數, std::function或lambda - 它應該適用於所有情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM