簡體   English   中英

模板函數中默認參數的實例化點

[英]Point of instantiation of default arguments in a template function

當從非模板上下文引用函數模板時,該標准允許在封閉的命名空間范圍聲明之后或在翻譯單元的末尾實例化函數模板: [temp.point]/1

對於函數模板特化、成員函數模板特化或類模板的成員函數或靜態數據成員的特化,如果特化是隱式實例化的,因為它是從另一個模板特化和它所在的上下文中引用的引用取決於模板參數,特化的實例化點是封閉特化的實例化點。 否則,這種特化的實例化點緊跟在引用該特化的命名空間范圍聲明或定義之后。

[溫度點]/8

函數模板、成員函數模板或類模板的成員函數或靜態數據成員的特化可以在翻譯單元內具有多個實例化點,並且除了上述實例化點之外,對於任何此類在翻譯單元內有一個實例化點的特化,翻譯單元的結尾也被認為是一個實例化點。 類模板的特化在翻譯單元內最多有一個實例化點。 任何模板的特化都可能在多個翻譯單元中具有實例化點。 如果根據一個定義規則,兩個不同的實例化點賦予模板特化不同的含義,則程序格式錯誤,無需診斷。

現在考慮這個最小的可重現示例:

#include <iostream>
#include <array>
struct A {};
std::array<char, 2> show(float, A)
{
    std::cout << "2\n";
    return {};
}
template<typename T>
struct Fun {
    decltype(show(0, T{})) b;
};
template <typename T>
void func(T, int c = sizeof(Fun<T>{}.b))
{
    show(0, T{});
    std::cout << c << '\n';
}
int main()
{
    func(A{});
}
char show(int, A)
{
    std::cout << "1\n";
    return {};
}

GCC 和 Clang 都輸出1 2 ( Godbolt )。

在這里, func<A>的實例化(在main觸發)有兩個實例化點:一個緊接在main之后(因此在第二個show之前),另一個在翻譯單元的末尾。 第一個1表示編譯器在翻譯單元的末尾實例化func<A> 然而,默認參數sizeof(Fun<T>{}.b)導致Fun<A>被實例化,第二個2表明Fun<A>在第二個show之前實例化。

現在,默認參數的實例化點被指定為func<A> : [temp.point]/2

如果以使用該函數模板或成員函數的默認參數定義的方式調用類模板的函數模板或成員函數,則默認參數的實例化點是函數模板的實例化點或成員函數專業化。

嗯……這好像暗示這兩個數字應該是一樣的。

我覺得我在這里錯過了一些東西。 有沒有什么細節我碰巧忽略了? 還是我犯了錯誤?

正如問題[temp.point]/8 中引用的那樣:

如果根據一個定義規則,兩個不同的實例化點賦予模板特化不同的含義,則程序格式錯誤,無需診斷。

根據單一定義規則,如果定義中使用的名稱的函數調用重載解析將產生定義外定義的不同實體,則兩個定義是不同的。 ( [basic.def.odr]/6.2 )

func<A>Fun<A> show的兩個調用的重載解析將根據func<A>的實例化點是緊接在main之后還是在翻譯單元的末尾來選擇不同的函數重載,兩者都是其中允許實例化點。

因此程序格式錯誤,不需要診斷

暫無
暫無

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

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