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

    这就是我的想法 - 但这对我来说是一个小问题,最重要的是让它为抽象类工作:) –

    相关问题