亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

是否可以編寫模板來檢查函數的存在?

是否可以編寫模板來檢查函數的存在?

天涯盡頭無女友 2019-05-24 15:12:24
是否可以編寫模板來檢查函數的存在?是否可以編寫一個模板來改變行為,具體取決于是否在類上定義了某個成員函數?這是我想寫的一個簡單例子:template<class T>std::string optionalToString(T* obj){     if (FUNCTION_EXISTS(T->toString))         return obj->toString();     else         return "toString not defined";}所以,如果class T已經toString()確定的話,就使用它; 否則,它沒有。我不知道怎么做的神奇部分是“FUNCTION_EXISTS”部分。
查看完整描述

5 回答

?
Smart貓小萌

TA貢獻1911條經驗 獲得超7個贊

是的,使用SFINAE,您可以檢查給定的類是否提供某種方法。這是工作代碼:

#include <iostream>struct Hello{
    int helloworld() { return 0; }};struct Generic {};    // SFINAE testtemplate <typename T>class has_helloworld{
    typedef char one;
    typedef long two;

    template <typename C> static one test( typeof(&C::helloworld) ) ;
    template <typename C> static two test(...);    public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };};int main(int argc, char *argv[]){
    std::cout << has_helloworld<Hello>::value << std::endl;
    std::cout << has_helloworld<Generic>::value << std::endl;
    return 0;}

我剛用Linux和gcc 4.1 / 4.3測試過它。我不知道它是否可以移植到運行不同編譯器的其他平臺


查看完整回答
反對 回復 2019-05-24
?
UYOU

TA貢獻1878條經驗 獲得超4個贊

這個問題很老,但是使用C ++ 11,我們有了一種新方法來檢查函數是否存在(或者確實存在任何非類型成員),再次依賴SFINAE:

template<class T>auto serialize_imp(std::ostream& os, T const& obj, int)
    -> decltype(os << obj, void()){
  os << obj;}template<class T>auto serialize_imp(std::ostream& os, T const& obj, long)
    -> decltype(obj.stream(os), void()){
  obj.stream(os);}template<class T>auto serialize(std::ostream& os, T const& obj)
    -> decltype(serialize_imp(os, obj, 0), void()){
  serialize_imp(os, obj, 0);}

現在進行一些解釋。首先,如果內部的第一個表達式無效(也就是說,函數不存在),我使用表達式SFINAEserialize(_imp)從重載解析中排除函數decltype。

void()是用來做的所有這些函數的返回類型void

如果兩者都可用,則該0參數用于優先選擇重載os << obj(文字0是類型的int,因此第一個重載是更好的匹配)。


現在,您可能需要一個特征來檢查函數是否存在。幸運的是,寫起來很容易。但是請注意,您需要為自己想要的每個不同的函數名自己編寫一個特征。

#include <type_traits>template<class>struct sfinae_true : std::true_type{};namespace detail{
  template<class T, class A0>
  static auto test_stream(int)
      -> sfinae_true<decltype(std::declval<T>().stream(std::declval<A0>()))>;
  template<class, class A0>
  static auto test_stream(long) -> std::false_type;} // detail::template<class T, class Arg>struct has_stream :
   decltype(detail::test_stream<T, Arg>(0)){};

實例。

并解釋。首先,sfinae_true是一個幫助器類型,它基本上與寫入相同decltype(void(std::declval<T>().stream(a0)), std::true_type{})。優點是它更短。
接下來,取決于簽入是否失敗,struct has_stream : decltype(...)從任一端std::true_typestd::false_type最后繼承。 最后,為您提供所傳遞的任何類型的“值”,而無需您知道如何構建它。請注意,這只能在未評估的上下文中使用,例如,和其他。decltypetest_stream
std::declvaldecltypesizeof


請注意,decltype不一定需要,因為sizeof(并且所有未評估的上下文)都獲得了增強。它只是decltype已經提供了一種類型,因此只是更清潔。這是一個sizeof重載的版本:

template<class T>void serialize_imp(std::ostream& os, T const& obj, int,
    int(*)[sizeof((os << obj),0)] = 0){
  os << obj;}

由于同樣的原因,intlong參數仍然存在。數組指針用于提供sizeof可以使用的上下文。


查看完整回答
反對 回復 2019-05-24
?
守著星空守著你

TA貢獻1799條經驗 獲得超8個贊

雖然這個問題已經有兩年了,但我還是敢補充一下。希望它能澄清以前無可爭議的優秀解決方案。我采用了Nicola Bonelli和Johannes Schaub的非常有用的答案,并將它們合并為一個解決方案,即恕我直言,更易讀,更清晰,不需要typeof擴展:

template <class Type>class TypeHasToString{
    // This type won't compile if the second template parameter isn't of type T,
    // so I can put a function pointer type in the first parameter and the function
    // itself in the second thus checking that the function has a specific signature.
    template <typename T, T> struct TypeCheck;

    typedef char Yes;
    typedef long No;

    // A helper struct to hold the declaration of the function pointer.
    // Change it if the function signature changes.
    template <typename T> struct ToString
    {
        typedef void (T::*fptr)();
    };

    template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*);
    template <typename T> static No  HasToString(...);public:
    static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));};

我用gcc 4.1.2檢查了它。這個功勞主要歸功于Nicola Bonelli和Johannes Schaub,如果我的回答可以幫助你,請給他們一個投票:)


查看完整回答
反對 回復 2019-05-24
  • 5 回答
  • 0 關注
  • 710 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號