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:
T
is public
T
is not abstractMy 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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With