2013-08-06 52 views
12

可以採用通過ADL發現的函數的地址嗎?是否可以取得ADL功能的地址?

例如:

template<class T> 
void (*get_swap())(T &, T &) 
{ 
    return & _________;  // how do I take the address of T's swap() function? 
} 

int main() 
{ 
    typedef some_type T; 
    get_swap<T>(); 
} 

回答

3

老實說,我不知道,但我朝說,這是不可能的傾向。

根據你想達到什麼,我可以建議一種解決方法。更確切地說,如果你只需要擁有相同的語義swap通過ADL調用的函數的地址,然後你可以使用這個:

template <typename T> 
void (*get_swap())(T&, T&) { 
    return [](T& x, T& y) { return swap(x, y); }; 
} 

例如,下面的代碼:

namespace a { 

    struct b { 
     int i; 
    }; 

    void swap(b& x, b& y) { 
     std::swap(x.i, y.i); 
    } 
} 

int main() { 

    auto f0 = (void (*)(a::b&, a::b&)) a::swap; 
    auto f1 = get_swap<a::b>(); 

    std::cout << std::hex; 
    std::cout << (unsigned long long) f0 << '\n'; 
    std::cout << (unsigned long long) f1 << '\n'; 
} 

編譯我的機器上的gcc 4.8.1(-std=c++11 -O3)給出:

4008a0 
4008b0 

相關的彙編代碼(objdump -dSC a.out)爲

00000000004008a0 <a::swap(a::b&, a::b&)>: 
    4008a0: 8b 07     mov (%rdi),%eax 
    4008a2: 8b 16     mov (%rsi),%edx 
    4008a4: 89 17     mov %edx,(%rdi) 
    4008a6: 89 06     mov %eax,(%rsi) 
    4008a8: c3      retq 
    4008a9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 

00000000004008b0 <void (*get_swap<a::b>())(a::b&, a::b&)::{lambda(a::b&, a::b&)#1}::_FUN(a::b&, a::b&)>: 
    4008b0: 8b 07     mov (%rdi),%eax 
    4008b2: 8b 16     mov (%rsi),%edx 
    4008b4: 89 17     mov %edx,(%rdi) 
    4008b6: 89 06     mov %eax,(%rsi) 
    4008b8: c3      retq 
    4008b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 

如可以看到的(分別位於0x4008a00x4008b0)由f0f1和指向的功能是二進制相同。與3.3版一起編譯時也是如此。

如果鏈接器可以做相同的COMDAT摺疊(ICF),我想我們甚至可以得到f0 == f1。 (更多關於ICF看到this後)。

+0

[好了,通過了所有的考試(http://coliru.stacked-crooked.com/view?id=46999fdc4c98b2092415c91172d44b12-cc73e281b3b6abc9bf6cf4f153b944a6) –