簡體   English   中英

使用默認參數作為模板類型的函數

[英]Function with default parameter as template type

我試圖使用一個默認參數的函數作為函數指針模板參數:

template <void (*F)()>
class A {};

void foo1(int a = 0) {}
void foo2() {}

int main() 
{
    //A<foo1> a1;   <-- doesn't work
    A<foo2> a2;
}

編譯器錯誤是:

main.cpp:7:7:錯誤:無法將模板參數'foo1'轉換為'void(*)()'

這是否有特定的語法? 還是特定的語言限制? 否則,替代方法是使用兩個單獨的函數而不是默認參數:

void foo1(int a) {}
void foo1() { foo1(0); }

更新我明白簽名是不同的,但我想知道是否有方法使這項工作方便,而無需使用默認參數修改所有功能?

foo1的簽名是void(int) ,而不是void() 這就是為什么它不能轉換為void(*)()

您將默認參數與重載混淆。

默認參數值不是函數類型的一部分。 你不能將foo1用作不帶參數的函數,因為它確實需要一個參數。 如果你沒有提及它,那么這個論點就會被填入,但它仍然存在。

涉及調度功能的解決方法聽起來像是一個很好的解決方案。 如果你需要它,它甚至可能會被模板化。

我很確定函數指針具有函數的簽名,所有默認參數都已擴展,函數指針無法轉換為具有不同簽名的函數指針。 在標准中找到這個是另一回事,但......

我認為標准中的相關條款是8.3.5 [dcl.fct]第6段:

...返回類型,參數類型列表,ref限定符和cv-qualifier-seq,但不是默認參數(8.3.6)或異常規范(15.4),是函數的一部分類型。 [注意:在指向函數的指針和函數的引用以及指向成員函數的指針的賦值和初始化期間,將檢查函數類型。 - 尾注]

請注意,根據8.3.6 [dcl.fct.default]第1段, 默認參數是form = value的人:

如果在參數聲明中指定了initializer子句,則此initializer子句將用作默認參數。 ...

根據C ++標准的8.3.6節,

如果在參數聲明中指定了表達式,則此表達式將用作默認參數。 默認參數將用於缺少尾隨參數的調用中。

由於A<foo1> 不是函數的調用,因此忽略默認參數。 事實上,除了函數的調用之外,它們在所有上下文中都被忽略

typedef void (*FFF)();
FFF x = foo1;

將不會編譯,並產生嘗試使用foo1作為模板參數時獲得的相同消息:

error: invalid conversion from ‘void (*)(int)’ to ‘void (*)()’

這是有道理的,因為評估默認參數是調用中的一個單獨步驟:

8.3.6.9:每次調用函數時都會計算默認參數。

默認參數的存在不會改變函數的簽名。 例如,您不能使用帶有默認參數的單參數函數來覆蓋無參數的虛擬成員函數。

它不會編譯因為foo1有簽名:

void foo1(int a);

你試圖堅持指向:

void F()

功能簽名不匹配。 foo1具有默認參數的事實不會更改函數的簽名(它仍然可以包含int )。

更通用的解決方案

我會說忘記模板,他們只限制你。

就個人而言,我解決回調問題的方法是使用帶參數綁定的 函數對象 它可以使用boost :: function庫完成,並使用boost :: bind (或std::bind1ststd::bind2nd )綁定默認參數。

這些boost庫也內置於新的C ++ 11標准中,如std::functionstd::bind

這是值得一看的,因為它讓你做一些非常好的事情,比如為函數提供默認參數,或者使用類成員函數作為回調。

我鏈接到的網站都有很多示例代碼,而boost鏈接都有教程。

暫無
暫無

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

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