讓我們考慮普通的完美轉發:
class Test
{
public:
Test() = default;
Test(Test const&) { std::cout << "copy\n"; }
Test(Test&&) { std::cout << "move\n"; }
};
void test(Test)
{ }
template <typename T>
void f(T&& t)
{
test(std::forward<T>(t));
}
int main()
{
std::cout << "expect: copy\n";
Test t;
f(t);
std::cout << "expect: move\n";
f(Test());
return 0;
}
到目前為止一切都很好。但是,如果我們現在引入一個函式指標,我會遇到我似乎無法宣告通用(轉發)參考的問題:
decltype(&f<Test>) ptr = &f<Test>;
// above produces ordinary r-value references
// making below fail already on compilation:
ptr(t);
模板函式指標也有問題:
template <typename T>
void(*ptr)(T&& t) = &f<T>; // again resolved to r-value reference
起初,它們也決議為純 r 值參考,此外,它們定義了一堆指標而不是單個指標,使得該方法在類范圍內無法使用:
class C
{
template <typename T>
void(*ptr)(T&& t); // fails (of course...)
};
所以現在的問題是:是否有可能通過函式指標進行間接完美轉發?
承認,已經擔心答案是“不”(并且目前回退到左值參考),但仍然希望在某個地方忽略了一些東西......
uj5u.com熱心網友回復:
第一個示例使用模板引數推導和參考折疊規則來計算正確的型別。當您顯式提供模板引數時,這將禁用推導,并且直接替換提供的型別,從而產生右值參考。
uj5u.com熱心網友回復:
轉發參考不僅僅是一個假設的概念。它是一種特定型別的右值參考的名稱,在模板引數推導中具有特殊的推導規則。
具體根據[temp.deduct.call]/3:
轉發參考是對不代表類模板的模板引數的 cv 非限定模板引數的右值參考(在類模板引數推導期間([over.match.class.deduct]))。如果 P 是轉發參考并且引數是左值,則使用型別“對 A 的左值參考”代替 A 進行型別推導。
除了這個特殊規則(以及[temp.deduct.type]中的另一個規則)之外,轉發參考的行為就像任何其他右值參考一樣。
特別是在為 提供模板引數時T,不會發生模板引數推導,而是直接執行替換。作為替代,應用了通常的參考折疊規則。
因此f<Test>將產生Test&&作為右值參考f<Test&>的函式引數,并將產生函式引數(從應用到Test&折疊)。&&Test&
這些也是在沒有顯式模板引數的函式呼叫中為右值引數和左值引數推匯出的模板引數。如果參考不是轉發參考,則T永遠不能推斷為參考,并且函式引數在替換后始終是右值參考。A參考中提到的特殊調整允許T將其推匯出為左值參考型別,以便折疊規則也將導致左值參考函式引數。
轉發參考只能存在于模板中。模板的函式或特化不能有轉發參考。它們在某種程度上不是與右值/左值參考不同的參考類別。它們僅通過為引數的不同值類別推斷出不同型別并為每個值類別生成不同的特化來在模板中作業。
因此,由于函式指標必須指向函式,而不是函式模板,因此在獲取函式指標時必須確定要選擇的引數值類別的兩種特化中的哪一種。
如果需要任何型別的推論,那么函式指標就無法提供。相反,應該使用 lambda 或仿函式型別,它可以執行推導,并且可以根據值類別選擇要呼叫的函式或函式模板特化。
uj5u.com熱心網友回復:
完美轉發需要推匯出模板引數。函式指標只能指向單個函式,不能指向一組多載,也不能指向函式模板。
您可以獲得指向 r 值參考實體化的函式指標:
decltype(&f<Test&&>) ptr1 = &f<Test&&>;
ptr1(Test()); // output: move
或左值實體化:
decltype(&f<Test&>) ptr2 = &f<Test&>;
ptr2(t); // output: copy
但不能同時對兩者。ptr1并且ptr2是指向不同型別函式的指標。
當您希望某些東西不僅包含單個函式而且包含多個多載時,您可以使用帶有成員函式的型別。例如使用 lambda 運算式:
auto fw = [](auto&& t){ test(std::forward<decltype(t)>(t)); };
fw(t); // output: copy
fw(Test()); // output: move
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/472141.html
