Syntax of a parameter extending two classes - c++

In Java, it's possible to declare that a parameter implements multiple interfaces. You have to use generics syntax, but you can:
public <T extends Appendable & Closeable> void spew(T t) {
t.append("Bleah!\n");
if (timeToClose())
t.close();
}
In C++, a common pattern is to use classes containing only pure virtual functions as interfaces:
class IAppendable {
public:
virtual void append(const std::string&) = 0;
};
class ICloseable {
public:
virtual void close() = 0;
};
And it's trivial to write a function that takes an ICloseable (this is just polymorphism):
void closeThis(ICloseable&);
But what is the signature of a function that takes a parameter which, as in the Java example, inherits from both ICloseable and IAppendable?

Here is how you'd write it using only standard facilities :
template <class T>
std::enable_if_t<
std::is_base_of<IAppendable, T>{} && std::is_base_of<ICloseable, T>{},
void
> closeThis(T &t) {
t.append("end");
t.close();
}
Live on Coliru
If there were more base classes, I'd advise crafting a more concise type trait to check them all in the enable_if :
constexpr bool allTrue() {
return true;
}
template <class... Bools>
constexpr bool allTrue(bool b1, Bools... bools) {
return b1 && allTrue(bools...);
}
template <class T, class... Bases>
struct all_bases {
static constexpr bool value = allTrue(std::is_base_of<Bases, T>{}...);
constexpr operator bool () const {
return value;
}
};
template <class T>
std::enable_if_t<
all_bases<T, IAppendable, ICloseable>{},
void
> closeThis(T &t) {
t.append("end");
t.close();
}

#Quentin's excellent answer prompted me to write a generalized, variadicinherits template. It allows you to easily specify an arbitrary number of base classes.
#include <type_traits>
template<class... T> struct inherits :
std::true_type
{};
template<class T, class Base1, class... Bases>
struct inherits<T, Base1, Bases...> :
std::conditional_t< std::is_base_of<Base1, T>{},
inherits<T, Bases...>,
std::false_type
>
{};
The first template parameter is the type to check, and the remaining parameters are the types that the first type must inherit from.
For example,
class A {};
class B {};
class C {};
template<class T>
std::enable_if_t<
inherits<T, A, B, C>{},
void
> foo(const T& t)
{
// ...
}
Here, whatever type T is passed as an argument to foo must inherit from A, B, and C.
Live on Coliru

Related

How to reduce recursive variadic inheritance code bloat?

Let's say I want to create a variadic interface with different overloads for the structs A,B,C:
struct A{};
struct B{};
struct C{};
template <typename ... Ts>
class Base;
template <typename T>
class Base<T>{
public:
virtual void visit(const T& t) const
{
// default implementation
}
};
template<typename T, typename ... Ts>
class Base<T, Ts...>: Base<T>, Base<Ts...>{
public:
using Base<T>::visit;
using Base<Ts...>::visit;
};
int main()
{
A a;
B b;
auto base = Base<A,B,C>{};
auto base2 = Base<A,C,B>{};
base.visit(a);
base2.visit(b);
}
Now funtionally Base<A,B,C> is identical to Base<A,C,B> but the compiler still generates the different combinations. Of course with more template parameters it gets worse.
I assume there is some meta programming magic which can cut this code bloat down.
One solution might be to define template<typename T, typename U> Base<T,U> in a way that it checks if Base<U,T> already exists. This could reduce at least some combinations and can probably be done by hand for triplets as well. But I am missing some meta programming magic and hoping for a more general approach.
Edit:
I would like to have the variadic Interface for a (simplified) use case like that:
class Implementation:public Base<A,B,C>
{
public:
void visit(const A& a) const
{
std::cout <<"Special implementation for type A";
}
void visit(const B& a) const
{
std::cout <<"Special implementation for type B";
}
// Fall back to all other types.
};
using BaseInterface = Base<A,B,C>;
void do_visit(const BaseInterface& v)
{
v.visit(A{});
v.visit(B{});
v.visit(C{});
}
int main()
{
std::unique_ptr<BaseInterface> v= std::make_unique<Implementation>();
do_visit(*v);
}
The reason why I want to do this is that there could be potentially a lot of types A,B,C,... and I want to avoid code duplication to define the overload for each type.
Base<A, B, C> instantiates Base<A>, Base<B, C>, Base<B>, Base<C>
and
Base<A, C, B> instantiates Base<A>, Base<C, B>, Base<B>, Base<C>
Whereas final nodes are needed, intermediate nodes increase the bloat.
You can mitigate that issue with:
template <typename T>
class BaseLeaf
{
public:
virtual ~BaseLeaf() = default;
virtual void visit(const T& t) const
{
// default implementation
}
};
template <typename... Ts>
class Base : public BaseLeaf<Ts>...
{
public:
using BaseLeaf<Ts>::visit...;
};
Demo
Base<A,B,C> and Base<A,C,B> are still different types.
To be able to have same type, they should alias to the same type, and for that, ordering Ts... should be done in a way or another.
Looks like the member function should be a template rather than the class.
struct A{};
struct B{};
struct C{};
class Foo {
public:
template<typename T>
void visit(const T& t) const
{
// default implementation
}
};
int main()
{
A a;
B b;
auto foo = Foo{};
foo.visit(a);
foo.visit(b);
}
https://godbolt.org/z/nTrYY6qcn
I'm not sure what is your aim, since there is not enough details. With current information I think this is best solution (there is a also a lambda which can address issue too).
It's necessary to enforce some sort of discipline on the order of template parameters. You can do this with a template variable and a few static_asserts:
#include <type_traits>
template <typename ... Ts>
class Base;
struct A
{
};
struct B
{
};
struct C
{
};
struct D
{
};
template <class T>
static constexpr int visit_sequence_v = -1;
template <>
constexpr int visit_sequence_v<A> = 0;
template <>
constexpr int visit_sequence_v<B> = 1;
template <>
constexpr int visit_sequence_v<C> = 2;
template <typename T>
class Base<T>{
public:
static_assert(visit_sequence_v<T> >= 0, "specialize visit_sequence_v for this type");
virtual void visit(const T& t) const
{
// do nothing by default
}
};
template<typename T1, typename T2>
class Base<T1, T2>: Base<T1>, Base<T2>
{
public:
static_assert(std::is_same_v<T1, T2> || visit_sequence_v<T1> < visit_sequence_v<T2>);
using Base<T1>::visit;
using Base<T2>::visit;
};
template<typename T1, typename T2, typename ... Ts>
class Base<T1, T2, Ts...>: Base<T1>, Base<T2, Ts...>
{
public:
static_assert(std::is_same_v<T1, T2> || visit_sequence_v<T1> < visit_sequence_v<T2>);
using Base<T1>::visit;
using Base<Ts...>::visit;
};
int main()
{
A a;
B b;
auto base = Base<A,B,C>{};
//auto base2 = Base<A,C,B>{}; // static_assert fails
//auto base3 = Base<A,B,C,D>{}; // forgot to specialize
base.visit(a);
}
Notice the point here is to cause a compilation failure if you get the order wrong. If someone has the chops to do a compile-time sort it may be possible to cobble up a traits class (or a template function that you can use decltype on the return type) that selects an implementation of Base in the correct order.
One alternative is to declare a full specialization of Base for every individual type that can be visited (supplying a "default implementation" for visit) and declare a static constexpr visit_sequence within each specialzation.
A problem inherent in your method is that in the case of multiple inheritance, visit can be ambiguous:
struct E: public A, public B
{
};
// 5 MiNuTES LATeR...
DescendantOfBase<A, B> a_b;
E e;
a_b.visit (e); // ambiguous

SFINAE and inheritance

I'm looking for a solution to a following problem:
#include <string>
class A
{
public:
template <typename T>
static typename std::enable_if<std::is_same<T, std::string>::value, void>::type foo(T val)
{
printf("std::string\n");
}
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
T::foo(arg...);
}
};
class B : public A
{
public:
template <typename T>
static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
{
printf("int\n");
}
};
int main()
{
std::string a;
int b = 0;
A::multiple<B>(a, b);
}
All works fine if both foo methods are in the same class or I force foo from proper class (A::foo for std::string and B::foo for int), however I need more than one class, because base class must be extendable. I can't use simple specialization, because I need more SFINAE features like detect for std::pair, std::tuple etc. I also don't want to move foo methods from a class to a namespace. Do you have any Idea how can I solve this issue?
Here B::foo hides A::foo, you need a using:
class B : public A
{
public:
using A::foo;
template <typename T>
static typename std::enable_if<std::is_same<T, int>::value, void>::type foo(T val)
{
printf("int\n");
}
};
But
From namespace.udecl#15.sentence-1:
When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting)
Return type doesn't count, so you have to use std::enable_if in parameter:
class A
{
public:
template <typename T>
static void foo(T val, std::enable_if_t<std::is_same<T, std::string>::value, int> = 0)
{
printf("std::string\n");
}
};
class B : public A
{
public:
using A::foo;
template <typename T>
static void foo(T val, std::enable_if_t<std::is_same<T, int>::value, int> = 0)
{
printf("int\n");
}
};
Demo
Note: you also have typo for
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
T::foo(arg...); // B::foo(string, int)
}
which should be
template<typename T, typename... Arg>
static void multiple(Arg&&... arg)
{
(T::foo(arg), ...); // B::foo(string), B::foo(int)
}

Detecting a member function in a class which uses CRTP

I am trying to customize a base classes' implementation based on the functions available in a child class using CRTP.
Basic idea of what I want:
// has_inc_function<Child, void> should detect the presence of a member function void Child::inc()
template<class Child, bool = has_inc_function<Child, void>::value>
struct base
{
// ... base implementation stuff
};
template<class Child>
struct base<Child, true>
{
// ... base specialization implementation stuff
};
struct empty : public base<empty>
{};
struct has_inc
{
void inc()
{}
};
struct has_inc_and_crtp : public base<has_inc_and_crtp>
{
void inc()
{}
};
struct has_inc_and_misuse_crtp : public base<has_inc_and_misuse_crtp, true>
{
void inc()
{}
};
struct has_inc_and_misuse_crtp2 : public base<has_inc_and_misuse_crtp, false>
{
void inc()
{}
};
struct no_inc_and_misuse_crtp : public base<no_inc_and_misuse_crtp, true>
{
};
int main()
{
static_assert(has_inc_function<empty, void>::value == false, "");
static_assert(has_inc_function<has_inc, void>::value == true, "");
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
static_assert(has_inc_function<has_inc_and_misuse_crtp, void>::value == true, "");
static_assert(has_inc_function<has_inc_and_misuse_crtp2, void>::value == true, "");
static_assert(has_inc_function<no_inc_and_misuse_crtp, void>::value == false, "");
}
I've tried a variety of different implementations for has_inc_function<Child, void>, but all of them seem to fail on the case has_inc_and_crtp, and I can't figure out why. I tested with several different compilers via Compiler Explorer, and they all seem to give the same results.
How would I implement has_inc_function so that it works as I would expect in all these test case, or is what I want just not possible?
Implementations I've tried
jrok's solution (Compiler Explorer link):
template <class C, class Ret>
struct has_increment<C, Ret>
{
private:
template <class T>
static constexpr auto check(T*) -> typename std::is_same<
decltype(std::declval<T>().inc()), Ret>::type;
template <typename> static constexpr std::false_type check(...);
typedef decltype(check<C>(nullptr)) type;
public:
static constexpr bool value = type::value;
};
TartanLlama's solution (Compiler Explorer link):
note: that is implementation doesn't match the return type. I've also included sample implementations of stuff in Library fundamentals TS v2 to make this work in C++14
struct nonesuch
{
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
namespace detail {
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
template <class Default, template<class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;
template<class...> struct disjunction : std::false_type { };
template<class B1> struct disjunction<B1> : B1 { };
template<class B1, class... Bn>
struct disjunction<B1, Bn...>
: std::conditional_t<bool(B1::value), B1, disjunction<Bn...>> { };
template <typename T>
using has_type_t = typename T::inc;
template <typename T>
using has_non_type_t = decltype(&T::inc);
template <typename T, class RetType>
using has_inc_function =
disjunction<is_detected<has_type_t, T>, is_detected<has_non_type_t, T>>;
Valentin Milea's solution (Compiler Explorer Link):
template <class C, class RetType>
class has_inc_function
{
template <class T>
static std::true_type testSignature(RetType (T::*)());
template <class T>
static decltype(testSignature(&T::inc)) test(std::nullptr_t);
template <class T>
static std::false_type test(...);
public:
using type = decltype(test<C>(nullptr));
static const bool value = type::value;
};
Boost TTI (I couldn't figure out how to get Boost to work with Compiler Explorer):
#include <boost/tti/has_member_function.hpp>
BOOST_TTI_TRAIT_HAS_MEMBER_FUNCTION(has_inc_function, inc);
What you want is in this form plainly not possible. The parent of a class has to be known before the class is complete, and hence before it is known whether the class has such a member function or not.
What you can do is a bit dependent on how different the different instantiations of base are. If they are basically the same interface with different implementation details, you can write another class that has the same interface and a variant member (std::variant is sadly C++17, but you could do the same with dynamic polymorphism) to which all calls are forwarded. Then the decision which to use can be done when instantiating.
You could also try something in this direction:
#include <type_traits>
#include <iostream>
template<class Child>
struct base {
int foo();
};
struct has_inc: base<has_inc> {
void inc();
};
struct has_not_inc: base<has_not_inc> {
};
template<class Child, class = std::void_t<decltype(std::declval<Child>().inc())>>
struct mock {
int foo(base<Child>*) { return 1;}
};
template<class Child>
struct mock<Child> {
int foo(base<Child>*) { return 0;}
};
template<class Child>
int base<Child>::foo() {
return mock<Child,void>().foo(this);
}
int main() {
has_inc h;
has_not_inc n;
std::cout << h.foo() << " " << n.foo() << '\n';
}
Here you only use the complete child of type in the definition, not in the declaration. To the point of the definition, the complete child is available, which it was not during declaration.
There are also other ways (I think, everything is not that easy) and what you can use really depends on your use-case, I would think.
PS: std::void_t is C++17, but it is only template<class...> using void_t = void;.
I've tried a variety of different implementations for has_inc_function<Child, void>, but all of them seem to fail on the case has_inc_and_crtp, and I can't figure out why.
The problem (if I understand correctly) is that, in the has_inc_and_crpt case, the value of has_inc_function is first evaluated to determine the default value for the Childs second template parameter
template<class Child, bool = has_inc_function<Child, void>::value>
struct base
that is when Child (that is has_inc_and_crpt) is still incomplete, so the value if false, and in the following use
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
remain false.
How would I implement has_inc_function so that it works as I would expect in all these test case, or is what I want just not possible?
A quick and dirty solution could be add an additional dummy defaulted template parameter to has_inc_function.
By example
// ................................VVVVVVV dummy and defaulted
template <typename C, typename RT, int = 0>
struct has_inc_function
then use it in base explicating a special (different from the default) parameter
// ........................................................V different from the default
template<class Child, bool = has_inc_function<Child, void, 1>::value>
struct base
So, when you use has_inc_functin in the static assert,
static_assert(has_inc_function<has_inc_and_crtp, void>::value == true, "");
the class is different, is evaluated in that moment and has_inc_and_crpt is detected with inc() method.
But this only resolve the problem at test case (static_assert()) level.
Still remain the problem (a problem that I don't how to solve) that, declaring base, the default value remain false. So (I suppose) has_inc_and_crpt still select the wrong base base.
The following is a full compiling example, following the jrok's solution.
#include <type_traits>
template <typename C, typename RT, int = 0>
struct has_inc_function
{
private:
template <typename T>
static constexpr auto check(T *) ->
typename std::is_same<decltype(std::declval<T>().inc()), RT>::type;
template <typename>
static constexpr std::false_type check(...);
using type = decltype(check<C>(nullptr));
public:
/// #brief True if there is an inc member function
static constexpr bool value = type::value;
};
template <typename Child, bool = has_inc_function<Child, void, 1>::value>
struct base
{ };
template <typename Child>
struct base<Child, true>
{ };
struct empty : public base<empty>
{ };
struct has_inc
{ void inc() {} };
struct has_inc_and_crtp : public base<has_inc_and_crtp>
{ void inc() {} };
struct has_inc_and_misuse_crtp : public base<has_inc_and_misuse_crtp, true>
{ void inc() {} };
struct has_inc_and_misuse_crtp2 : public base<has_inc_and_misuse_crtp, false>
{ void inc() {} };
struct no_inc_and_misuse_crtp : public base<no_inc_and_misuse_crtp, true>
{ };
template <typename C, typename RT>
constexpr auto hif_v = has_inc_function<C, RT>::value;
int main ()
{
static_assert(hif_v<empty, void> == false, "");
static_assert(hif_v<has_inc, void> == true, "");
static_assert(hif_v<has_inc_and_crtp, void> == true, "");
static_assert(hif_v<has_inc_and_misuse_crtp, void> == true, "");
static_assert(hif_v<has_inc_and_misuse_crtp2, void> == true, "");
static_assert(hif_v<no_inc_and_misuse_crtp, void> == false, "");
}

Change class API depending on template parameter at class creation

I was looking to create a class that under specific template instantiation would expose a different API. It has common functions, but a few should be disabled in the case that the user will use a specific instantiation of the class. Something like this:
VarApi<T1> v1;
v1.common();
v1.funcA1();
// v1.funcA2(); // ERROR
v1.funcA1_2();
VarApi<T2> v2;
v1.common();
// v2.funcA1(); // ERROR
v2.funcA2();
v2.funcA1_2();
VarApi<T3> v3;
v3.common();
// v2.funcA1(); // ERROR
// v2.funcA2(); // ERROR
// v1.funcA1_2(); // ERROR
I found that you could achieve this with SFINAE and std::enable_if like this:
enum Type { T1, T2, T3 };
template <Type TType> struct VarApi {
void common() { }
template <Type T = TType,
typename = typename std::enable_if<T == T1>::type>
void funcA1() { }
template <Type T = TType,
typename = typename std::enable_if<T == T2>::type >
void funcA2() { }
template <Type T = TType,
typename = typename std::enable_if<T == T1 || T == T2>::type >
void funcA1_2() { }
template <Type T = TType,
typename = typename std::enable_if<T == T3>::type >
void funcA3() { }
};
This works and achieves the functionality above. The problem is that the user can still override this with:
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
Is there a way to prevent this case?
This works and achieves the functionality above. The problem is that the user can still override this with:
VarApi<T2> v2;
v2.funcA1<T1>(); // NOT ERROR
Is there a way to prevent this case?
Sure.
You can impose that T and TType are the same type
template <Type T = TType,
typename = typename std::enable_if<
std::is_same<T, T1>::value
&& std::is_same<T, TType>::value>::type>
void funcA1() { }
This prevent the template "hijacking".
You can exploit inheritance to provide desired functions. With CRTP, you access functionality of the original class in the func_provider by self pointer.
template<class T, class Derived> struct func_provider;
template<class Derived>
struct func_provider<int, Derived> {
void funcA1() {
auto self = static_cast<Derived*>(this);
// do something with self
}
};
template<class Derived> struct func_provider<double, Derived> { void funcA2() {} };
template<class T>
struct foo : public func_provider<T, foo<T>> {};
int main() {
foo<int> f;
foo<double> g;
f.funcA1();
// f.funcA2(); // Error
g.funcA2();
// g.funcA1(); // Error
}
EDIT:
This version allows the user to implement function for multiple types in one place, user can combine types together:
template<class... Ts> struct types {};
template<class Types, class T> struct is_in : public std::false_type {};
template<class... Ts, class T>
struct is_in<types<T, Ts...>, T> : public std::true_type {};
template<class... Ts, class T0, class T>
struct is_in<types<T0, Ts...>, T> : public is_in<types<Ts...>, T> {};
template<class Derived, bool B, class T> struct func_provider {};
template<class Derived, class T, class... Ts>
struct func_collector
: public func_provider<Derived, is_in<Ts, T>::value, Ts>...
{};
// implement functions for int
template<class Derived>
struct func_provider<Derived, true, types<int>> {
void funcA1() {
auto self = static_cast<Derived*>(this);
// do something with self
}
};
// implement functions for double
template<class Derived>
struct func_provider<Derived, true, types<double>> { void funcA2() {} };
// implement functions for both int and double
template<class Derived>
struct func_provider<Derived, true, types<int, double>> { void funcA1_2() {} };
template<class T>
struct foo : public func_collector<foo<T>, T,
// pull desired functions
types<int>, types<double>, types<int, double>>
{
void common() {}
};
int main() {
foo<int> f;
foo<double> g;
f.common();
f.funcA1();
f.funcA1_2();
// f.funcA2(); // Error
g.funcA2();
g.funcA1_2();
// g.funcA1(); // Error
}
Solution 1
One way to achieve what you ask for is to use tempalte specialization and dependent base classes to offer the optional functionalities.
// I'm using E for enum. I find TType a bit misleading, since T usually stands for Type
template< Type EType >
struct VarApiBase { }; // empty by default
template< >
struct VarApiBase<T1> {
void funcA1() { }
};
template< >
struct VarApiBase<T2> {
void funcA2() { }
};
template <Type TType>
struct VarApi : VarApiBase<TType> {
void funcA1_2() { }
};
template <>
struct VarApi<T3> { };
I'm not particularly fond of this solution. Because it becomes complex to provide shared functions (I put funcA1_2 in VarApi, and not in the base, and then specialized VarApi again to disable it for T3, but this is forcing you to explicitly specialize every time you add a new EType value. You could get around it with an enabler for the specialization, but it again become complex if you have more intricate sharing).
If you need it, you can give VarApiBase access to VarApi by declaring it a friend in VarApi.
Solution 2
As a cheap alternative to all of this, you may just add a static_assert inside your functions:
template <Type ETypeInner = EType >
void funcA1_2() {
static_assert(ETypeInner==EType);
static_assert(EType == T1 || EType == T2);
}
If you really need SFINAE, you can still put the ==T1 || ==T2 condition in the template
template <Type ETypeInner = EType,
typename = typename std::enable_if<ETypeInner == T1 || ETypeInner == T2>::type >
void funcA1_2() {
static_assert(ETypeInner==EType);
}
but be aware it will make compilation slower.
Solution 3
Probably, the cleanest way would be to have explicit specializations and utility functions.
In VarApi.h:
struct VarApiImpl;
template< Type EType >
struct VarApi; // undefined
// Ideally, VarApiCommon shouldn't need to be a template
template< Type EType >
struct VarApiCommon {
// you can put here members and functions which common to all implementations, just for convenience.
void common() { /* ... */ }
private:
// You can do this if you need access to specialization-specific members.
// Ideally, if a function is common, it should only need common members, though.
VarApi<EType> & Derived() { return static_cast<VarApi<EType>&>(*this); }
VarApi<EType> const& Derived() const { return static_cast<VarApi<EType> const&>(*this); }
};
template<>
struct VarApi<T1> : VarApiCommon<T1> {
friend VarApiImpl;
friend VarApiCommon<T1>;
void funcA1();
void funcA1_2();
};
template<>
struct VarApi<T2> : VarApiCommon<T2> {
friend VarApiImpl;
friend VarApiCommon<T2>;
void funcA2();
void funcA1_2();
};
template<>
struct VarApi<T3> : VarApiCommon<T3> {
friend VarApiCommon<T3>;
};
In VarApi.cpp:
struct VarApiImpl final {
// Here go the functions which are only shared by some specializations
template< Type EType >
static void funcA1_2(VarApi<EType>& vapi) {
// Just for sanity. Since this function is private to the .cpp, it should be impossible to call it inappropriately
static_assert(EType==T1 || EType==T2);
// ...
}
};
void VarApi<T1>::funcA1() { /* ... */ }
void VarApi<T1>::funcA1_2() { VarApiImpl::funcA1_2(*this); }
void VarApi<T2>::funcA2() { /* ... */ }
void VarApi<T2>::funcA1_2() { VarApiImpl::funcA1_2(*this); }
It gets as verbose as C++ can be, but at least you have explicit interfaces clearly stating what's offered and what's not, without having to read a bunch of enable_ifs.
Solution 4
Ultimately, I would suggest you to look more carefully at your requirements, to see if they can't be expressed as a proper class hierarchy, based on the features each enum value represents. C++ even has virtual inheritance, if you need to avoid duplicate bases. For instance, that'd be possible in your example:
struct VarApiCommon {
void common();
};
struct VarApi12 : VarApiCommon {
void funcA1_2();
};
template< Type EType >
struct VarApi; // undefined
template<>
struct VarApi<T1> : VarApi12 {
void funcA1();
};
template<>
struct VarApi<T2> : VarApi12 {
void funcA2();
};
template<>
struct VarApi<T2> : VarApiCommon {
void funcA3();
};
If you had a funcA2_3, for instance, you may still be able to do it this way:
struct VarApiCommon {
void common();
};
struct VarApi12 : virtual VarApiCommon {
void funcA1_2();
};
struct VarApi23 : virtual VarApiCommon {
void funcA2_3();
};
template< Type EType >
struct VarApi; // undefined
template<>
struct VarApi<T1> : VarApi12 {
void funcA1();
};
template<>
struct VarApi<T2> : VarApi12, VarApi23 {
void funcA2();
};
template<>
struct VarApi<T2> : VarApi23 {
void funcA3();
};
Much depends on the members.
My suggestion is based on you being able to provide the implementation, but wanting to hide it.
Have a base implementation, which implements everything
template <class X> class Base
{
public:
void A();
void B();
void C();
void D();
void E();
};
Have a derived class which inherits protected, but then publishes public all the common methods from the base
template <class X> class Mid: protected Base<X>
{
public:
using Base::A;
using Base::B;
using Base::C;
// D & E are contentious
};
Have the actual published class, where each variant T1, T2, T3 is specialised.
These classes all publicly inherit from the second class, but then public friend publish the methods they do support.
template <class X> class Top: public Mid<X> {};
template <> class Top<X1>: public Mid<X1>
{
public:
using Base::D;
// Can't get E
};
template <> class Top<X2>: public Mid<X2>
{
public:
// Can't get D
using Base::E;
};
Gains: The methods you want to hide are not accessible. There is no template function magic.
Losses: The rules for publishing are arbitrary, and not driven by 'readable' FINAE at all. You also can't easily use inheritance to build rules either, though you might be able to do a LikeX second template argument.

conditional (SFINAE) override

I'm trying to do this:
struct A
{
virtual int f() const { return 0; }
};
template <typename T>
struct B : A
{
template <typename U = T,
typename std::enable_if<...some condition involving U...>::type>
int f() const { return 1; }
};
Caveat, I can't inherit class templates (use static overrides). Is this sort of construct allowed and can the template member B::f() override the member A::f()?
Try this:
template <typename T, typename=void>
struct B : A
{
...
};
temlate <typename T>
struct B<T, typename std::enable_if<...some condition...>::type>:
A
{
virtual int f() const override { return 1; }
};
where we have two versions of B<T>, one for which the condition is true (the enable_if one), one for which the condition is false (the default one).
If you wanted to be able to reuse your default B implementation, you could even do this:
template <typename T, typename=void>
struct B : A
{
...
};
template <typename T>
struct B<T, typename std::enable_if<...some condition...>::type>:
B<T, bool>
{
virtual int f() const override { return 1; }
};
where we inherit from the "false" case in the "true" case. But that is a bit dirty to me -- I'd rather put the common implementation in some third spot (B_impl) rather than that hack. (That also lets you static assert that the second argument is void in the first case of B).