簡體   English   中英

ABI 重整名稱中的 C++ 模板參數依賴 decltype

[英]C++ template-argument dependent decltype in ABI mangled name

考慮以下函數:

template <typename A, typename B>
auto Min(A&& a, B&& b)
        -> decltype(a < b ? std::forward<A>(a) : std::forward<B>(b))
{
    return a < b ? std::forward<A>(a) : std::forward<B>(b);
}

片段Min(0, 1)導致模板被實例化為Min<int, int> 奇怪的是,我的代碼中帶有 g++ 和 clang 的Min的損壞名稱是_Z3MinIiiEDTqultfp_fp0_cl7forwardIT_Efp_Ecl7forwardIT0_Efp0_EEOS0_OS1_ (又名: decltype (({parm#1}<{parm#2})?((forward<int>)({parm#1})) : ((forward<int>)({parm#2}))) Min<int, int>(int&&, int&&) )。 換句話說,用於推斷返回類型的表達式是損壞的 name 的一部分 就我個人而言,我期望一些更理智的東西: _Z3MinIiiET_OS0_OT0_ (又名: int Min<int, int>(int&&, int&&) )。 為什么不是這樣?


似乎 g++ 只在實際需要的情況下放置decltype表達式,因為這些形式都是_Z3Maxii

  • auto Max(int x, int y) -> int
  • auto Max(int x, int y) -> decltype(0)

gcc 使用“Italium C++ ABI”進行 mangling ,它指定

如果decltype的操作數表達式不依賴實例化,則直接對結果類型進行編碼。 例如:

 int x; template<class T> auto f(T p)->decltype(x); // The return type in the mangling of the template signature // is encoded as "i". template<class T> auto f(T p)->decltype(p); // The return type in the mangling of the template signature // is encoded as "Dtfp_E". void g(int); template<class T> auto f(T p)->decltype(g(p)); // The return type in the mangling of the template signature // is encoded as "DTcl1gfp_E".

第三個示例是 OP 的簡化版本,它也直接對整個表達式進行編碼,因為它依賴於實例化。 實例化相關定義為

如果表達式是類型相關的或值相關的,或者它具有類型相關或值相關的子表達式,則該表達式是實例化相關的。 例如,如果p是一個類型相關的標識符,則表達式sizeof(sizeof(p))既不依賴於類型,也不依賴於值,而是依賴於實例化(如果替換后可能會變成無效的)模板參數p結果證明具有不完整的類型)。 類似地,如果源代碼形式包含依賴實例化的表達式,則在源代碼中表達的類型是依賴於實例化的 例如,類型形式double[sizeof(sizeof(p))] (帶有p類型相關標識符)是實例化相關的

關鍵是依賴於實例化的表達式“在替換后可能會變得無效”,這可能是它們在重整中以未評估形式保留的原因。

如果重載函數模板,這些函數模板產生的函數(稱為函數模板特化)需要不同。 因此,C++ 標准規定函數模板特化的簽名包括生成特化的函數模板的簽名。

否則,如果兩個模板都實例化具有相同函數類型的函數,它們就會發生沖突。

我對https://stackoverflow.com/a/13296666/53974感到困惑,所以我做了一些實驗,證實了答案。

只要兩個模板不同,它們的特化就可以共存,即使重載決議無法在它們之間進行選擇; 所以損壞的名稱包括模板簽名。

由於無法選擇重載決議,范圍內的最新相關聲明似乎掩蓋了較早的聲明。 在下面的示例中,這兩次可見notfun1notfun具有相同的源代碼但調用不同的特化,並且template void fun<long>(long); 指的是兩個實例中的不同模板。 (我已經通過檢查此來源的反匯編及其變體來確認兩者)。

template<typename T> T var = {};
template long var<long>;
// long var; // Error

void fun(long) {}

template<typename T> void fun(T) {}
template void fun<long>(long); // void fun<long>(long)

void notfun1() {
  fun(1L);
  fun<long>(2); // Calls void fun<long>(long)
}

template<typename T> struct identity { using type = T; };
template<typename T> void fun(typename identity<T>::type);
template void fun<long>(long); // Generates void fun<long>(identity<long>::type)
//template void fun<long>(typename identity<long>::type); //Ditto, can't write both

void notfun() {
  fun(1L);
  fun<long>(2); // Calls void fun<long>(identity<long>::type)

}

template<typename T> void fun(typename identity<T>::type) {}

int main() {}

下面,為方便起見,在Mac x86_64上進行反匯編; 如果你仔細看,你會想要專注於callq目標。

$ c++filt __Z3funIlEvN8identityIT_E4typeE
void fun<long>(identity<long>::type)

$ c++filt __Z3funIlEvT_
void fun<long>(long)

$ g++ -fvisibility=hidden -std=c++17 spec.cpp -o spec; objdump -C --disassemble spec

spec:   file format Mach-O 64-bit x86-64


Disassembly of section __TEXT,__text:

0000000100003f40 fun(long):
100003f40: 55                           pushq   %rbp
100003f41: 48 89 e5                     movq    %rsp, %rbp
100003f44: 48 89 7d f8                  movq    %rdi, -8(%rbp)
100003f48: 5d                           popq    %rbp
100003f49: c3                           retq
100003f4a: 66 0f 1f 44 00 00            nopw    (%rax,%rax)

0000000100003f50 void fun<long>(long):
100003f50: 55                           pushq   %rbp
100003f51: 48 89 e5                     movq    %rsp, %rbp
100003f54: 48 89 7d f8                  movq    %rdi, -8(%rbp)
100003f58: 5d                           popq    %rbp
100003f59: c3                           retq
100003f5a: 66 0f 1f 44 00 00            nopw    (%rax,%rax)

0000000100003f60 notfun1():
100003f60: 55                           pushq   %rbp
100003f61: 48 89 e5                     movq    %rsp, %rbp
100003f64: bf 01 00 00 00               movl    $1, %edi
100003f69: e8 d2 ff ff ff               callq   -46 <__Z3funl>
100003f6e: bf 02 00 00 00               movl    $2, %edi
100003f73: e8 d8 ff ff ff               callq   -40 <__Z3funIlEvT_>
100003f78: 5d                           popq    %rbp
100003f79: c3                           retq
100003f7a: 66 0f 1f 44 00 00            nopw    (%rax,%rax)

0000000100003f80 notfun():
100003f80: 55                           pushq   %rbp
100003f81: 48 89 e5                     movq    %rsp, %rbp
100003f84: bf 01 00 00 00               movl    $1, %edi
100003f89: e8 b2 ff ff ff               callq   -78 <__Z3funl>
100003f8e: bf 02 00 00 00               movl    $2, %edi
100003f93: e8 08 00 00 00               callq   8 <__Z3funIlEvN8identityIT_E4typeE>
100003f98: 5d                           popq    %rbp
100003f99: c3                           retq
100003f9a: 66 0f 1f 44 00 00            nopw    (%rax,%rax)

0000000100003fa0 void fun<long>(identity<long>::type):
100003fa0: 55                           pushq   %rbp
100003fa1: 48 89 e5                     movq    %rsp, %rbp
100003fa4: 48 89 7d f8                  movq    %rdi, -8(%rbp)
100003fa8: 5d                           popq    %rbp
100003fa9: c3                           retq
100003faa: 66 0f 1f 44 00 00            nopw    (%rax,%rax)

0000000100003fb0 _main:
100003fb0: 55                           pushq   %rbp
100003fb1: 48 89 e5                     movq    %rsp, %rbp
100003fb4: 31 c0                        xorl    %eax, %eax
100003fb6: 5d                           popq    %rbp
100003fb7: c3                           retq

暫無
暫無

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

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