2011-05-25 103 views
3

我有一個sfinae類,它測試一個類是否是解析器規則(AX解析器生成器庫)。 如果P滿足解析器規則要求,axe::is_rule<P>::value應評估爲true。解析器規則必須具有以下部件的功能之一,以一對迭代器和返回axe::result<Iterator>:如何編寫SFINAE來測試解析器規則?

template<class Iterator> 
axe::result<Iterator> P::operator()(Iterator, Iterator); 

,或者它的專業化,或者非模板對於某些類型的圖表

axe::result<CharT*> P::operator()(CharT*, CharT*); 

,或const以上版本。理論上,可以有一個以上的超載operator(),儘管實際上對於具有上述簽名之一的單個operator()的測試就足夠了。

不幸的是,is_rule目前的實施只處理一些情況,但不是全部情況。有一些不幸的類,該失敗is_rule測試:

#define AXE_ASSERT_RULE(T)\ 
    static_assert(axe::is_rule<typename std::remove_reference<T>::type>::value, \ 
    "type '" #T "' is not a rule"); 

例如,以下不幸類型測試失敗:

struct unfortunate 
{ 
    axe::result<const unsigned char*> 
    operator()(const unsigned char*, const unsigned char*); 
}; 

AXE_ASSERT_RULE(unfortunate); 

// or same using lambda 
auto unfortunate1 = [](const unsigned char*, const unsigned char*) 
->axe::result<const unsigned char*> {}; 
AXE_ASSERT_RULE(decltype(unfortunate1)); 


typedef std::vector<char>::iterator vc_it; 
struct unfortunate2 { axe::result<vc_it> operator()(vc_it, vc_it) const; }; 
AXE_ASSERT_RULE(unfortunate2); 

typedef axe::result<const char*> (unfortunate3)(const char*, const char*); 
AXE_ASSERT_RULE(unfortunate3); 

struct rule { template<class I> axe::result<I> operator()(I, I); }; 
class unfortunate4 : public rule {}; 
AXE_ASSERT_RULE(unfortunate4); 
在AX

當前的解決方案是包裝那些在轉發封套( class r_ref_t),當然這會產生句法瑕疵(畢竟,解析器生成器都是關於語法糖的)。

如何修改is_rule中的sfinae測試來涵蓋上述不幸的情況?

回答

5

我認爲is_rule的API是不夠的。例如unfortunate只有在與const unsigned char*類型的迭代器一起使用時纔是規則。如果您使用unfortunateconst char*,那麼它不起作用,因此不是一個規則,對吧?

話雖這麼說,如果你改變了API來:

template <class R, class It> struct is_rule; 

那麼我認爲這是C++ 11可行的。下面是一個原型:

#include <type_traits> 

namespace axe 
{ 

template <class It> 
struct result 
{ 
}; 

} 

namespace detail 
{ 

struct nat 
{ 
    nat() = delete; 
    nat(const nat&) = delete; 
    nat& operator=(const nat&) = delete; 
    ~nat() = delete; 
}; 

struct any 
{ 
    any(...); 

    nat operator()(any, any) const; 
}; 

template <class T> 
struct wrap 
    : public any, 
     public T 
{ 
}; 

template <bool, class R, class It> 
struct is_rule 
{ 
    typedef typename std::conditional<std::is_const<R>::value, 
             const wrap<R>, 
             wrap<R>>::type W; 

    typedef decltype(
       std::declval<W>()(std::declval<It>(), std::declval<It>()) 
        ) type; 

    static const bool value = std::is_convertible<type, axe::result<It>>::value; 
}; 

template <class R, class It> 
struct is_rule<false, R, It> 
{ 
    static const bool value = false; 
}; 

} // detail 

template <class R, class It> 
struct is_rule 
    : public std::integral_constant<bool, 
         detail::is_rule<std::is_class<R>::value, R, It>::value> 
{ 
}; 

struct unfortunate 
{ 
    axe::result<const unsigned char*> 
    operator()(const unsigned char*, const unsigned char*); 
}; 

#include <iostream> 

int main() 
{ 
    std::cout << is_rule<unfortunate, const unsigned char*>::value << '\n'; 
    std::cout << is_rule<unfortunate, const char*>::value << '\n'; 
} 

對於我這種打印出:

1 
0 

我所做的規則稍微更寬鬆的比你指定:返回類型僅須隱式轉換爲axe::result<It>。如果你真的想要它是完全axe::result<It>然後只是在std::is_same sub我std::is_convertible

我也製作is_rule派生自std::integral_constant。這對於標籤調度可以非常方便。例如:

template <class T> 
void imp(T, std::false_type); 

template <class T> 
void imp(T, std::true_type); 

template <class T> 
void foo(T t) {imp(t, is_rule<T, const char*>());} 
+0

不幸的是,'is_rule'類不能採用迭代器類型,因爲沒有辦法指定它。當創建規則表達式時,迭代器類型是未知的,不能被指定。例如,(運算符&see http://tinyurl.com/3kmmcmh)表達式'auto rule = A & B;'是迭代器不可知的,規則A和B可以採取各種迭代器形式或者是複合規則本身,但是我必須能夠爲任何兼容的迭代器調用'rule(i1,i2)'。只要所有規則都實現了模板化的'operator()',我很好,否則(重要的是lambda函數)''is_rule'測試不幸失敗。 – 2011-05-25 22:20:59

+0

如果你想確定一個有限的迭代器集合,你可以修改上面的代碼來檢查任何有限的迭代器集合,如果規則適用於任何一組迭代器,則返回true。 – 2011-05-25 22:24:35

+0

我明白你的意思了。它會嚴重誇大代碼,每個複合規則(並且有很多)必須爲每個參數測試所有可能迭代器的所有可能組合。像這樣:'template r_and_t < typename std :: enable_if :: type,It1> :: value | is_rule :: type,It2> :: value, R1> :: type, typename std :: enable_if :: type,It1> :: value | is_rule :: type,It2> :: value, R2> :: type > operator&(R1 && r1,R2 && r2);'... – 2011-05-25 22:54:27