簡體   English   中英

為什么指針衰減優先於推導的模板?

[英]Why does pointer decay take priority over a deduced template?

假設我正在編寫一個函數來打印字符串的長度:

template <size_t N>
void foo(const char (&s)[N]) {
    std::cout << "array, size=" << N-1 << std::endl;
}

foo("hello") // prints array, size=5

現在,我想擴展foo以支持數組:

void foo(const char* s) {
    std::cout << "raw, size=" << strlen(s) << std::endl;
}

但是事實證明,這破壞了我最初的預期用法:

foo("hello") // now prints raw, size=5

為什么? 不需要模板到指針的轉換,而模板是完全匹配的嗎? 有沒有辦法確保我的數組函數被調用?

這種(符合標准的)歧義的根本原因似乎在於轉換成本:重載解析試圖最小化將參數轉換為相應參數所執行的操作。 但是,數組實際上是指向其第一個元素的指針,並裝飾有一些編譯時類型信息。 數組到指針的轉換不會比保存數組本身的地址或初始化對它的引用花費更多。 從這個角度看,歧義性似乎是合理的,盡管從概念上講它是不直觀的(可能會低於標准)。 實際上,此論點適用於所有左值轉換,如下面的引用所建議。 另一個例子:

void g() {}

void f(void(*)()) {}
void f(void(&)()) {}

int main() {
    f(g); // Ambiguous
}

以下是必填標准語。 如果某些函數模板不是專門化的函數,則它們比那些在其他方面都同樣匹配的函數優先(請參閱[over.match.best] /(1.3),(1.6))。 在我們的例子中,執行的轉換是數組到指針的轉換,這是具有精確匹配等級的左值轉換(根據[over.ics.user]中的表12)。 [over.ics.rank] / 3:

  • 如果滿足以下條件,則標准轉換序列S1比標准轉換序列S2更好。

    • S1S2的適當子序列(比較13.3.3.1.1定義的規范形式的轉換序列, 不包括任何左值變換 ;同一性轉換序列被視為任何非同一性轉換序列的子序列),或者不是那個,

    • S1的等級比S2的等級好,或者S1S2的等級相同,並且可以通過以下段落中的規則加以區分;或者,如果不是,

    • [..]

第一個要點不包括轉換(因為它是左值轉換)。 第二個要求排名不存在,因為兩個轉換的排名都完全相同; “以下段落中的規則”,即[over.ics.rank] / 4中的內容,也不涵蓋數組到指針的轉換。
因此,不管您相信與否,兩個轉換序列中的任何一個都不比另一個更好,因此選擇了char const* -overload。


可能的解決方法:將第二個重載也定義為功能模板,然后啟動部分排序並選擇第一個重載。

template <typename T>
auto foo(T s)
  -> std::enable_if_t<std::is_convertible<T, char const*>{}>
{
    std::cout << "raw, size=" << std::strlen(s) << std::endl;
}

演示

暫無
暫無

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

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