检测(可能是抽象的)基类的受保护的构造方法 [英] detecting protected constructors of (possibly abstract) base class
问题描述
我正在尝试C ++ 11的新功能。在我的设置中,我真的很想使用继承的构造函数,但是不幸的是,还没有编译器实现这些构造函数。因此,我试图模拟相同的行为。我可以这样写:
template< class T>
类包装器:public T {
public:
template< typename ... As>
Wrapper(As& ... as):T {std :: forward< As>(as)...} {}
// ... T的不错补充。
};。
这在大多数情况下都有效。有时,使用 Wrapper
类的代码必须使用SFINAE来检测 Wrapper< T>
的方式。建。但是,存在以下问题:就重载解析而言, Wrapper< T>
的构造函数将接受任何参数-但编译失败(这是<如果不能使用这些类型构造 T
类型,则不会被SFINAE覆盖。
I试图使用 enable_if
模板< typename ...作为,类型名称std :: enable_if< std :: is_constructible< T,作为&& ...> :: value,int> :: type = 0>
包装器(As&& ... as)// ...
只要
-
T
的适当构造函数为public
-
T
不是抽象的
我的问题是:如何摆脱以上两个限制?
我试图通过检查克服第一个约束(使用SFINAE和 sizeof()
)是否表达式 new T(std :: declval< As&>()... )
在 Wrapper< T>
内格式正确。但这当然是行不通的,因为派生类可以使用其基类受保护的构造方法的唯一方法是在成员初始化列表中。
对于第二个方法,我什么都不知道,这是我需要的,因为有时是 Wrapper
实现了 T的抽象功能
,使其成为完整类型。
我想要一个解决方案,
- 根据标准是正确的
- 可在gcc-4.6。*,gcc-4.7。*或clang-3。* 中使用b
谢谢!
本地GCC(4.7,rubenvb提供)。 Gide on ideone会打印一些已实现的编译器内部错误。
我不得不公开 Experiment
类的实现细节,因为某些原因(闻起来很香就像一个错误),我的GCC版本抱怨它们是私有的,即使只有类本身才使用它。
#include <实用程序>
template< typename T,typename Ignored>
struct Ignore {typedef T type; };
结构EatAll {
template< typename ... T>
EatAll(T&& ...){}
};
template< typename T>
struct实验:T {
public:
typedef char yes [1];
typedef char no [2];
static void check1(T const&);
static void check1(EatAll);
//如果此SFINAE失败,则T接受
template< typename ... U>
静态自动检查(int,U& ... u)
-> typename忽略< 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< type(Experiment :: check(0,std :: declval< U>()...))),
yes& :: value,int> :: type = 0>
Experiment(U& ... u):T {std :: forward< U>(u)...}
{}
};
//测试
struct AbstractBase {
protected:
AbstractBase(int,float);
virtual void f()= 0;
};
struct Annoyer {Annoyer(int); };
void x(Experiment< AbstractBase>);
无效x(Annoyer);
int main(){
x({42});
x({42,43.f});
}
更新:该代码也适用于Clang。
I am experimenting with the new features of C++11. In my setup I would really love to use inheriting constructors, but unfortunately no compiler implements those yet. Therefore I am trying to simulate the same behaviour. I can write something like this:
template <class T>
class Wrapper : public T {
public:
template <typename... As>
Wrapper(As && ... as) : T { std::forward<As>(as)... } { }
// ... nice additions to T ...
};
This works... most of the time. Sometimes the code using the Wrapper
class(es) must use SFINAE to detect how such a Wrapper<T>
can be constructed. There is however the following issue: as far as overload resolution is concerned, the constructor of Wrapper<T>
will accept any arguments -- but then compilation fails (and this is not covered by SFINAE) if the type T
cannot be constructed using those.
I was trying to conditionally enable the different instantiations of the constructor template using enable_if
template <typename... As, typename std::enable_if<std::is_constructible<T, As && ...>::value, int>::type = 0>
Wrapper(As && ... as) // ...
which works fine as long as:
- the appropriate constructor of
T
ispublic
T
is not abstract
My question is: how to get rid of the above two constraints?
I tried to overcome the first by checking (using SFINAE and sizeof()
) whether the expression new T(std::declval<As &&>()...)
is well-formed within Wrapper<T>
. But this, of course, does not work, because the only way a derived class can use its base's protected constructor is in the member initialization list.
For the second one, I have no idea whatsoever -- and it is the one I need more, because sometimes it is the Wrapper
which implements the abstract functions of T
, making it a complete type.
I want a solution which:
- is correct according to the standard
- works in any of gcc-4.6.*, gcc-4.7.* or clang-3.*
Thanks!
This appears to work fine on my local GCC (4.7, courtesy of rubenvb). GCC on ideone prints several "implemented" compiler internal errors though.
I had to make the "implementation details" of the Experiment
class public, because for some reasons (which smells like a bug), my version of GCC complains about them being private, even though only the class itself uses it.
#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});
}
Update: The code also works on Clang.
这篇关于检测(可能是抽象的)基类的受保护的构造方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!