2016-07-13 58 views
2

如何檢查會員功能是否存在,是否不是繼承?檢查會員功能是否存在,是否繼承SFINAE

我需要這解決歧義爲以下示例:

A型或者具有一個foo()bar()成員函數。 Callercall爲給定類型存在的那個。但是,DerivedWithBar繼承自BaseWithFoofoo(),但定義了它自己的bar()。因此,Caller不知道要調用哪個函數。

我需要一種方法來給予非繼承foo優先於繼承bar(),但我不知道如何檢查一個成員函數是否被繼承。

#include <iostream> 

struct BaseWithFoo 
{ 
    template <typename T> void foo(T&&){std::cout << "Base::foo" << std::endl;} 
}; 

struct DerivedWithBar : public BaseWithFoo 
{ 
    template <typename T> void bar(T&&){std::cout << "DerivedWithBar::bar" << std::endl;} 
}; 

struct DerivedWithFoo : public BaseWithFoo 
{ 
    template <typename T> void foo(T&&){std::cout << "DerivedWithFoo::foo" << std::endl;} 
}; 

struct EmptyDerived : public BaseWithFoo {}; 

struct BaseWithBar 
{ 
    template <typename T> void bar(T&&){std::cout << "BaseWithBar::bar" << std::endl;} 
}; 


struct Caller 
{ 
    template <typename T> 
    auto call(T&& x) -> decltype(x.foo(*this), void()) 
    { 
     x.foo(*this); 
    } 

    template <typename T> 
    auto call(T&& x) -> decltype(x.bar(*this), void()) 
    { 
     x.bar(*this); 
    } 
}; 

int main() 
{ 
    Caller c; 
    c.call(BaseWithFoo()); 
    c.call(DerivedWithFoo()); 
    c.call(DerivedWithBar()); 
    c.call(EmptyDerived()); 
    c.call(BaseWithBar()); 
} 

live example

期望的輸出:

Base::foo 
DerivedWithFoo::foo 
DerivedWithBar::bar 
Base::foo 
BaseWithBar::bar 
+0

您是否知道要測試的函數的簽名('void U :: foo(Caller&)')? – Jarod42

+0

@ Jarod42簽名是你寫的,但是它是一個模板函數,所以它的需要是通用的 –

回答

2

發現了一種方法,通過比較類型成員函數指針的繼承和非繼承的成員函數之間進行區分。

以下是我的完整問題(「給予非繼承成員函數優先於繼承的成員函數」)的部分解決方案。這將只調用非繼承foo或非繼承bar

struct Caller 
{  
    template <typename T> 
    auto call(T&& x) -> decltype(x.foo(*this), 
     std::enable_if_t< 
      std::is_same< 
       decltype(&T::template foo<decltype(*this)>), 
       void (T::*)(decltype(*this)) 
      >::value 
     >()) 
    { 
     x.foo(*this); 
    } 

    template <typename T> 
    auto call(T&& x) -> decltype(x.bar(*this), 
     std::enable_if_t< 
      std::is_same< 
       decltype(&T::template bar<decltype(*this)>), 
       void (T::*)(decltype(*this)) 
      >::value 
     >()) 
    { 
     x.bar(*this); 
    } 
}; 

live example

+1

你可以添加* priority *來解決其他部分:[Demo](http://coliru.stacked-crooked的.com /一個/ b2e3e5512ef241c1)。 – Jarod42

+0

@ Jarod42謝謝,我只是輸入類似的東西(基於[這個答案](http://stackoverflow.com/a/38283990/678093))。 –

0

了一堆模板,我們可以爲它遵循得到它:

#include<iostream> 
#include<type_traits> 
#include<utility> 

struct BaseWithFoo 
{ 
    template <typename T> void foo(T&&){std::cout << "Base::foo" << std::endl;} 
}; 

template<typename T> 
struct DerivedWithBarT : public T 
{ 
    template <typename U> void bar(U&&){std::cout << "DerivedWithBar::bar" << std::endl;} 
}; 

using DerivedWithBar = DerivedWithBarT<BaseWithFoo>; 

template<typename T> 
struct DerivedWithFooT : public T 
{ 
    template <typename U> void foo(U&&){std::cout << "DerivedWithFoo::foo" << std::endl;} 
}; 

using DerivedWithFoo = DerivedWithFooT<BaseWithFoo>; 

template<typename T> 
struct EmptyDerivedT : public T {}; 

using EmptyDerived = EmptyDerivedT<BaseWithFoo>; 

struct BaseWithBar 
{ 
    template <typename T> void bar(T&&){std::cout << "BaseWithBar::bar" << std::endl;} 
}; 

struct EmptyBase {}; 

template<typename...> 
using void_t = void; 

template<typename, typename = void_t<>> 
struct HasFoo: std::false_type {}; 

template<typename T, template<typename> class U> 
struct HasFoo<U<T>, void_t<decltype(&U<EmptyBase>::template foo<T>)>>: std::true_type {}; 

template<typename, typename = void_t<>> 
struct HasBar: std::false_type {}; 

template<typename T, template<typename> class U> 
struct HasBar<U<T>, void_t<decltype(&U<EmptyBase>::template bar<T>)>>: std::true_type {}; 

template<typename T> 
struct BarOverFoo { 
    static constexpr bool value = HasBar<T>::value && !HasFoo<T>::value; 
}; 

template<typename T> 
struct FooOverBar { 
    static constexpr bool value = HasFoo<T>::value && !HasBar<T>::value; 
}; 

template<typename T> 
struct Both { 
    static constexpr bool value = HasFoo<T>::value && HasBar<T>::value; 
}; 

template<typename T> 
struct None { 
    static constexpr bool value = !HasFoo<T>::value && !HasBar<T>::value; 
}; 

struct Caller 
{ 
    template <typename T> 
    std::enable_if_t<FooOverBar<T>::value> 
    call(T&& x) 
    { 
     x.foo(*this); 
    } 

    template <typename T> 
    std::enable_if_t<BarOverFoo<T>::value> 
    call(T&& x) 
    { 
     x.bar(*this); 
    } 

    template <typename T> 
    std::enable_if_t<Both<T>::value> 
    call(T&& x) 
    { 
     x.bar(*this); 
    } 

    template <typename T> 
    std::enable_if_t<None<T>::value> 
    call(T&& x) 
    { 
     callInternal(std::forward<T>(x)); 
    } 

private: 
    template <typename T> 
    auto callInternal(T&& x) -> decltype(x.foo(*this), void()) 
    { 
     x.foo(*this); 
    } 

    template <typename T> 
    auto callInternal(T&& x) -> decltype(x.bar(*this), void()) 
    { 
     x.bar(*this); 
    } 
}; 

int main() 
{ 
    Caller c; 
    c.call(BaseWithFoo()); 
    c.call(DerivedWithFoo()); 
    c.call(DerivedWithBar()); 
    c.call(EmptyDerived()); 
    c.call(BaseWithBar()); 
} 

符合您的要求,根據調整call方法。
我設置了一些默認設置,我不確定是否可以。

+0

不幸的是,我不能指望派生類型是模板 –