2016-03-11 112 views
3

我想創建一個重載的模板,如果一個類包含它,則運行一個函數Foo(),否則它不執行任何操作。函數模板的C++ Decltype

我一直在試圖運行它這樣

template <typename T, typename U> 
decltype(std::declval<T>().Foo()) TriggerFoo(T* t, U& u) 
{ 
    t->Foo(u); 
} 
template <typename T, typename U> 
void TriggerFoo(T* t, U& u) 
{ 
    std::cout << "Does not have Foo()" << std::endl; 
} 

int main() 
{ 
    A a; 
    B b; 
    U u;  // Some type 

    TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()". 
    TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()". 

    return 0; 
} 

目前,這兩個類都傳遞給了「不具有美孚()」實例。它編譯,但顯然它不工作,這很可能是因爲我不明白declval。我也嘗試過使用非模板函數,但它仍然不起作用。

任何幫助將不勝感激。

+0

http://stackoverflow.com/questions/257288/is-it-possible-to-write-ac-template-to-check-for-a-functions-existence –

+0

我很感謝答案,它是有幫助的,但我不想檢查自己該函數是否包含該類型。理想情況下,我想使它成爲通用的,以便通過檢查它是否包含Foo()來知道要調用哪個模板,而不必創建另一個類/結構,例如has_foo。 – mojo1mojo2

回答

1

有你的方法有兩個基本問題:

decltype(std::declval<T>().Foo()) 

這將永遠不會被成功地解決,因爲有問題的Foo()將始終以一個參數。這部分應該是:

decltype(std::declval<T>().Foo(std::declval<U &>())) 

但現在你會遇到不同的問題:當類實現Foo(),模板分辨率將變得模糊。可以使用模板功能。

所以,你需要間接的另一個層次,不同優先級的模板:

#include <iostream> 
#include <type_traits> 

class A 
{ 
public: 
    template <typename U> 
    void Foo(U& u) 
    { 
     std::cout << "Has Foo()" << std::endl; 
     // Modify u 
    } 
}; 

class B 
{ 
    // Does not contain Foo() 
}; 

template <typename T, typename U, typename Z=decltype(std::declval<T>().Foo(std::declval<U &>()))> 
void DoTriggerFoo(T* t, U& u, int dummy) 
{ 
    t->Foo(u); 
} 

template <typename T, typename U> 
void DoTriggerFoo(T* t, U& u, ...) 
{ 
    std::cout << "Does not have Foo()" << std::endl; 
} 

template <typename T, typename U> 
void TriggerFoo(T *t, U &u) 
{ 
    DoTriggerFoo(t, u, 0); 
} 

class U {}; 

int main() 
{ 
    A a; 
    B b; 
    U u;  // Some type 

    TriggerFoo<A, U>(&a, u); // I want to print "Has Foo()". 
    TriggerFoo<B, U>(&b, u); // Prints "Does not have Foo()". 

    return 0; 
} 

結果用gcc 5.3:

$ ./t 
Has Foo() 
Does not have Foo() 

PS:

std::declval<T &>().Foo(std::declval<U &>()) 

這是可能的這將會更好,與你的實際課程。

+0

非常感謝!我之前有過模棱兩可的問題,但不知道如何解決這個問題。 – mojo1mojo2

+0

只是想知道,因爲我想深入瞭解模板元編程,請您解釋一下虛擬變量的用途?我玩過代碼,例如刪除「int dummy」,將「...」更改爲「int dummy」等,並且大部分它變得模糊不清。 爲什麼「typename Z = decltype ...」不能自行工作? – mojo1mojo2

+1

這不僅僅是虛擬變量本身,也是其他模板函數中相應的'...'參數佔位符。包裝器爲相應的參數傳遞一個0。當decltype解析成功時,兩個模板函數都會解析,但具有'...'參數佔位符的函數的優先級低於聲明明確的int類型參數的優先級。這解決了歧義。 –