Reputation: 7490
I need conditional using member declaration.
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template <typename T>
struct A : public B<is_default_constructible<T>::value> {
using B<is_default_constructible<T>::value>::foo();
void foo(int) {}
};
This obviously doesn't work, because B<bool>::foo
is not defined
in half the cases. How can I achieve that? To have B<>::foo()
visible in A<T>
scope beside foo(int)?
Upvotes: 5
Views: 769
Reputation: 5729
enable_if
can't be used for that. You need to specialize struct A
too.
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct A : public B<default_constructible> {
using B<default_constructible>::foo;
void foo(int) {}
};
template<typename T>
struct A<T, false> : public B<false> {
void foo(int) {}
};
If foo(int)
will have the same functionality in both cases, you may want to derive it from another base struct:
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template<typename T>
struct C {
void foo(int) {}
};
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct A : public B<default_constructible>, public C<T> {
using B<default_constructible>::foo;
using C<T>::foo;
};
template<typename T>
struct A<T, false> : public B<false>, public C<T> {
using C<T>::foo;
};
Finally, to remove that bool from struct A
's template parameters, you may want to forward the responsibility of selecting the overloads of foo
to a base class. This also has the advantage of not duplicating code for other struct A
's members you may want to add.
#include <type_traits>
template <bool> struct B;
template <> struct B<true> { void foo(); };
template <> struct B<false> { };
template<typename T>
struct C {
void foo(int) {}
};
template <typename T, bool default_constructible = std::is_default_constructible<T>::value>
struct base_A : public B<default_constructible>, public C<T> {
using B<default_constructible>::foo;
using C<T>::foo;
};
template<typename T>
struct base_A<T, false> : public B<false>, public C<T> {
using C<T>::foo;
};
template <typename T>
struct A : public base_A<T> {
// Other members.
};
Upvotes: 0
Reputation: 2124
This is my solution. I'm sure it's won't be the best but it gets the job done.
struct A {
void foo(int) {}
};
struct A
should contain methods you want defined in both cases.
template <bool> struct B;
template <> struct B<false> : A {};
template <> struct B<true> : A {
using A::foo;
void foo() {}
};
In case of B<false>
, only void foo(int)
is defined. In case of B<true>
, both void foo(int)
and void foo()
are defined.
template <typename T>
struct C : public B<is_default_constructible<T>::value> {};
Now I don't have to worry about B<is_default_constructible<T>::value>::foo()
not being defined in certain cases.
class D { D() = delete; };
int main()
{
C<int> c1;
c1.foo(1234);
c1.foo();
// both methods are defined for C<int>
C<D> c2;
c2.foo(1234);
// c2.foo(); // undefined method
return 0;
}
Upvotes: 0