2009-03-01 32 views
2

我需要爲stl算法設計謂詞,例如find_if,count_if。stl算法的C++「智能」謂詞

namespace lib 
{ 
    struct Finder 
    { 
     Finder(const std::string& name): 
      name_(name) 
     { 
     } 

     template< typename TElement > 
     bool operator(const TElement& element) 
     { 
      return element.isPresent(name_); 
     } 

     /* template< typename TElement > 
     bool operator(const TElement& element) 
     { 
      const Data& data = element.getData(); 
      return data.isPresent(name_); 
     }*/ 
    }; 
} 

但我需要它根據TElement中某些特定方法的存在具有不同的運算符()。就像它有「getData」我想檢查這些數據,如果它沒有,我會做一些其他的行動。

我知道SFINAE。但是我沒有boost ::關於這個項目。 因此,無論是模板「has_method」的一些簡單實現,還是您知道其他一些設計解決方案。

我不能指出特定的類型和簡單的重載,因爲我想把這個謂詞放到項目庫中,它不知道那些具有「getData」方法的特定類。

只要沒有命名空間,類類特徵的解決方案就很好。 「lib」命名空間中的Predicate Finder和「getData」中的類位於「program」命名空間中。

謝謝。

+0

你可以添加一個示例用法來說明行爲如何改變? – dirkgently 2009-03-01 17:56:49

回答

3

爲什麼要使用模板方法?如果有很多類的類型,只需使用您想要基於的特定類或公共基類即可。

例如

struct Finder 
{ 
    Finder(const std::string& name): 
     name_(name) 
    { 
    } 

    bool operator(const IsPresentBaseClass& element) 
    { 
     return element.isPresent(name_); 
    } 

    bool operator(const GetDataBaseClass& element) 
    { 
     const Data& data = element.getData(); 
     return data.isPresent(name_); 
    } 
}; 

如果這種格局發生了很多不同的類類型和您使用謂詞,你可以在模板本身謂詞之前知道的類型。

例如

template<class T1, class T2> 
struct Finder 
{ 
    Finder(const std::string& name): 
     name_(name) 
    { 
    } 

    bool operator(const T1& element) 
    { 
     return element.isPresent(name_); 
    } 

    bool operator(const T2& element) 
    { 
     const Data& data = element.getData(); 
     return data.isPresent(name_); 
    } 
}; 

或者您可以使用的另一種方法是使用某種類特徵來保存信息。

例如

struct UseIsPresent 
{ 
    template<class T> 
    static bool CompareElement(const T& element, const std::string& name) 
    { 
     return element.isPresent(name); 
    } 
}; 

struct UseGetData 
{ 
    template<class T> 
    static bool CompareElement(const T& element, const std::string& name) 
    { 
     const Data& data = element.getData(); 
     return data.isPresent(name); 
    } 
}; 

// default to using the isPresent method 
template <class T> 
struct FinderTraits 
{ 
    typedef UseIsPresent FinderMethodType; 
}; 

// either list the classes that use GetData method 
// or use a common base class type, e.g. UseGetData 
template <> 
struct FinderTraits<UseGetData> 
{ 
    typedef UseGetData FinderMethodType; 
}; 

struct Finder 
{ 
    Finder(const std::string& name) 
    : name_(name) 
    { 
    } 

    template<class T> 
    bool operator()(const T& element) 
    { 
     return FinderTraits<T>::FinderMethodType::CompareElement<T>(element, name_); 
    } 

    std::string name_; 
}; 

的所有這些方法的缺點是,在某些時候,你需要知道的類型才能夠起來分成使用哪種方法。

+0

是的。我忘了指出這個問題。請稍後閱讀編輯部分。 – 2009-03-01 18:49:58

+0

你知道使用謂詞的具體類型嗎?你可以在這些類上找到Finder結構體的模板?看來你需要指定一些具體的類型。 – 2009-03-01 19:38:22

1

你可以看看Veldhuizen's homepageswitch模板。你可以用這個來選擇確切的操作符?

+0

std :: find_if必須選擇正確的一個。 – 2009-03-01 18:13:37

0

你的類型是否來自於「功能類型」(例如類型「has_function1」),它將作爲java接口工作,並且你有機會,因爲SFINAE可以用來測試一種類型是否可以轉換爲另一種類型。

如果你有興趣,我可以看看它,並給你一個更詳細的答案。

編輯: 我知道你說你沒有使用Boost庫,但有什麼阻止你獲得所需要得到提振幾個文件:: is_convertible工作?沒有什麼特別要編譯!

+0

那些不同的類型沒有關係。他們在邏輯和意義上有共同之處,但他們不在等級制中。 – 2009-03-01 18:23:01

0

Boost不是魔法;使用SFINAE相當簡單:

template< typename TElement > 
    bool operator(const TElement& element, ...) 
    { 
     return element.isPresent(name_); 
    } 

    template< typename TElement > 
    bool operator(const TElement& element, const Data& data = element.getData()) 
    { 
     return data.isPresent(name_); 
    } 

如果SFINAE不編譯,它將刪除第二個重載。重載解析會挑選第二個,如果它編譯,因爲......是一個更糟糕的匹配。