15

我正在試驗C++ 11的新功能。在我的設置中,我真的很喜歡使用繼承構造函數,但不幸的是沒有編譯器實現這些。因此我試圖模擬相同的行爲。我可以寫這樣的東西:檢測受保護的構造函數(可能是抽象的)基類

template <class T> 
class Wrapper : public T { 
    public: 
    template <typename... As> 
    Wrapper(As && ... as) : T { std::forward<As>(as)... } { } 
    // ... nice additions to T ... 
}; 

這個工程...大部分時間。有時使用類的代碼必須使用SFINAE來檢測如何構建這樣的Wrapper<T>。然而,存在以下問題:就重載解析而言,Wrapper<T>的構造函數將接受任何參數 - 但如果不能使用這些參數構造T,則編譯失敗(並且這是而非由SFINAE覆蓋)。

我試圖用enable_if

template <typename... As, typename std::enable_if<std::is_constructible<T, As && ...>::value, int>::type = 0> 
    Wrapper(As && ... as) // ... 

其中只要正常工作條件使構造模板的不同實例:

  • T適當的構造函數是public
  • T不是抽象的

我的問題是:如何擺脫上述兩個約束?

我試圖克服所述第一通過檢查(使用SFINAE和sizeof())是否表達new T(std::declval<As &&>()...)被內Wrapper<T>合式。但是,這當然不起作用,因爲派生類可以使用其基類的受保護構造函數的唯一方式是在成員初始化列表中。

對於第二個,我不知道 - 這是我需要更多,因爲有時它是Wrapper,它實現了T的抽象函數,使它成爲一個完整的類型。

我想的溶液,其中:。根據在任何GCC-4.6的標準

  • 作品

    • 是正確*,GCC-4.7 *或鐺-3 *

    謝謝!

  • +0

    我很忙,但也許http://stackoverflow.com/questions/8984013/can-sfinae-detect-private-access-violations可以在這裏幫助,我不會指望gcc 4.6正確雖然 – PlasmaHH

    +1

    訪問控制在這裏有點棘手:如果使用'sizeof()',編譯器將檢查整個表達式,包括訪問 - 但是然後從表達式**的上下文中檢查訪問**,這會失敗受保護的構造函數;除了'sizeof'之外的所有東西都只能在重載解析和類型推斷的層面上工作,所以訪問衝突不會觸發SFINAE - 但是,我看不出用構造函數做什麼,因爲它不能作爲模板參數傳遞。至於編譯器支持,如果上面的任何**接受代碼,我會很高興。 –

    回答

    12

    這似乎在我的本地GCC(4.7,由rubenvb提供)上正常工作。 G ide on ideone打印出幾個「已實施」的編譯器內部錯誤。因爲某些原因(這聽起來像一個bug),我的GCC版本抱怨說它們是私人的,儘管只有這個類本身使用它。所以我不得不使用這個類的公共類。

    #include <utility> 
    
    template<typename T, typename Ignored> 
    struct Ignore { typedef T type; }; 
    
    struct EatAll { 
        template<typename ...T> 
        EatAll(T&&...) {} 
    }; 
    
    template<typename T> 
    struct Experiment : T { 
    public: 
        typedef char yes[1]; 
        typedef char no[2]; 
    
        static void check1(T const&); 
        static void check1(EatAll); 
    
        // if this SFINAE fails, T accepts it 
        template<typename ...U> 
        static auto check(int, U&&...u) 
        -> typename Ignore<no&, 
         decltype(Experiment::check1({std::forward<U>(u)...}))>::type; 
    
        template<typename ...U> 
        static yes &check(long, U&&...); 
    
    public: 
        void f() {} 
        template<typename ...U, 
          typename std::enable_if< 
          std::is_same<decltype(Experiment::check(0, std::declval<U>()...)), 
              yes&>::value, int>::type = 0> 
        Experiment(U &&...u):T{ std::forward<U>(u)... } 
        {} 
    }; 
    
    // TEST 
    
    struct AbstractBase { 
        protected: 
        AbstractBase(int, float); 
        virtual void f() = 0; 
    }; 
    
    struct Annoyer { Annoyer(int); }; 
    
    void x(Experiment<AbstractBase>); 
    void x(Annoyer); 
    
    int main() { 
        x({42}); 
        x({42, 43.f}); 
    } 
    

    更新:該代碼也可以在鏘。

    +0

    非常聰明地使用模棱兩可,我必須承認。讓我檢查它是否適用於我的設置。順便說一下,它如何處理私有基礎構造函數? –

    +0

    @GrzegorzHerman私有基礎構造函數未被選中。我必須承認:(所以它會認爲轉換是可能的 –

    +0

    這就是我的想法 - 但這對我來說是一個小問題,最重要的是讓它爲抽象類工作:) –

    相關問題