簡體   English   中英

為什么模板參數推導因重載函數而失敗?

[英]Why does template argument deduction fail with overloaded function?

我有一個模板函數,它應該使用函數指針和參數,然后使用給定的參數調用函數指針(讓我們稱之為Invoke )。 但是,當我使用重載函數作為參數調用模板函數時,模板推導失敗。

我使用了enable_if,只有一個重載才有效,但這沒有幫助。

#include <string>
#include <type_traits>

void foo(int, int){}
void foo(std::string, std::string) {}

template <bool Val1, bool Val2, bool ...Rest>
struct And
{
    enum {value = And<Val1 && Val2, Rest...>::value};
};
template <bool Val1, bool Val2>
struct And<Val1, Val2>
{
    enum {value = Val1 && Val2};
};

template <typename ...Params, typename ...Args, typename = typename std::enable_if<
    And<std::is_convertible<Args, Params>::value...>::value
>::type>
void Invoke(void (*fn)(Params...), Args ...args){}

int main() {
    Invoke(&foo, "a", "b");
    return 0;
}

試試ideone

當兩個重載都存在時,編譯器會mismatched argument pack lengths while expanding 'std::is_convertible<Args, Params>::value'時抱怨mismatched argument pack lengths while expanding 'std::is_convertible<Args, Params>::value' 當我注釋掉int重載時,程序編譯得很好,當我注釋掉std::string重載時,推理會失敗,因為const char[]不能隱式轉換為int

標准(C ++ 17標准的第17.8.2.1.6.2節)說明如下:

如果參數是重載集(不包含函數模板),則嘗試使用集合中的每個成員進行試驗參數推導。 如果僅對其中一個重載集成員進行推導成功,則該成員將用作推導的參數值。 如果對重載集的多個成員進行推導成功,則將該參數視為非推導上下文。

所以我希望編譯器會嘗試int重載,其中演繹會失敗。 當它嘗試std::string重載時,推論會成功。

由於演繹只對其中一個重載集成員成功,我希望它會繼續進行,就好像int重載不存在一樣,並且編譯會像其他重載被注釋掉時那樣成功,但是失敗。

我哪里錯了?

參考標准將不勝感激。

&foo不是函數指針,而是重載集。 你必須明確:

Invoke(static_cast<void(*)(std::string, std::string)>(&foo), "a", "b");

為了簡化失敗的enable_if ,您可以使用一個未指定的函數指針類型,使用可變參數的arugment包,並檢查is_invocablehttpsis_invocable

這里的問題是有多個功能可以工作。 Params...的推論Params...將在您進入模板的SFINAE部分之前發生。 當它試圖從void (*fn)(Params...)推導出Params..它匹配void foo(int, int)void foo(std::string, std::string) 由於它找到了多個匹配項,因此17.8.2.1.6.2聲明它被視為非推導的上下文。

由於它無法推斷出類型,因此您會遇到硬停止錯誤。 SFINAE僅在模板參數扣除步驟之后發生,在這種情況下無法達到。

暫無
暫無

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

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