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).
Related
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
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}
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
Let's say, I have six types, and they each belong in a conceptual category.
Here is a diagram that shows this:
Or Perhaps a more specific example for you:
I want to write two functions that will handle all 6 types.
Types in "Category 1" get handled a certain way, and types in "Category 2" get handled a different way.
Let's get into the code.
First, I'll create the six types.
//Category 1 Types
class Type_A{};
class Type_B{};
class Type_C{};
//Category 2 Types
class Type_D{};
class Type_E{};
class Type_F{};
Next, I'll create two type traits so that the category of the type can be discovered at compile time.
/* Build The Category 1 Type Trait */
//Type_A Type Trait
template <typename T>
struct Is_Type_A {
static const bool value = false;
};
template <>
struct Is_Type_A<Type_A> {
static const bool value = true;
};
//Type_B Type Trait
template <typename T>
struct Is_Type_B {
static const bool value = false;
};
template <>
struct Is_Type_B<Type_B> {
static const bool value = true;
};
//Type_C Type Trait
template <typename T>
struct Is_Type_C {
static const bool value = false;
};
template <>
struct Is_Type_C<Type_C> {
static const bool value = true;
};
//Category 1 Type Trait
template <typename T>
struct Is_Type_From_Category_1 {
static const bool value = Is_Type_A<T>::value || Is_Type_B<T>::value || Is_Type_C<T>::value;
};
/* Build The Category 2 Type Trait */
//Type_D Type Trait
template <typename T>
struct Is_Type_D {
static const bool value = false;
};
template <>
struct Is_Type_D<Type_D> {
static const bool value = true;
};
//Type_E Type Trait
template <typename T>
struct Is_Type_E {
static const bool value = false;
};
template <>
struct Is_Type_E<Type_E> {
static const bool value = true;
};
//Type_F Type Trait
template <typename T>
struct Is_Type_F {
static const bool value = false;
};
template <>
struct Is_Type_F<Type_F> {
static const bool value = true;
};
//Category 1 Type Trait
template <typename T>
struct Is_Type_From_Category_2 {
static const bool value = Is_Type_D<T>::value || Is_Type_E<T>::value || Is_Type_F<T>::value;
};
Now that I have two type traits to distinguish what category each of the six types fall into, I want to write two functions. One function will accept everything from Category 1, and the other function will accept everything from Category 2. Is there a way to do this without creating some kind of dispatching function? Can I find a way to have only two functions; one for each category?
EDIT: I have tried to use enable_if like this, but such an attempt will result in a compiler error.
//Handle all types from Category 1
template<class T ,class = typename std::enable_if<Is_Type_From_Category_1<T>::value>::type >
void function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T ,class = typename std::enable_if<Is_Type_From_Category_2<T>::value>::type >
void function(T t){
//do category 2 stuff to the type
return;
}
Edit 2: I've tried the code provided in the link, but this isn't a yes or no decision on whether or not to call the function. It's which function do I call, given two type traits. This would be a redefinition error.
//Handle all types from Category 2
template<class T, class dummy = typename std::enable_if< Is_Type_From_Category_1<T>::value, void>::type>
void function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T, class dummy = typename std::enable_if< Is_Type_From_Category_2<T>::value, void>::type>
void function(T t){
//do category 2 stuff to the type
return;
}
Two functions signatures are not allowed to differ only by the default value of a template parameter. What would happen if you explicitly called function< int, void >?
Usual usage of enable_if is as the function return type.
//Handle all types from Category 1
template<class T >
typename std::enable_if<Is_Type_From_Category_1<T>::value>::type
function(T t){
//do category 1 stuff to the type
return;
}
//Handle all types from Category 2
template<class T >
typename std::enable_if<Is_Type_From_Category_2<T>::value>::type
function(T t){
//do category 2 stuff to the type
return;
}
I think using tag despatch would be easier than SFINAE.
template<class T>
struct Category;
template<>
struct Category<Type_A> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_B> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_C> : std::integral_constant<int, 1> {};
template<>
struct Category<Type_D> : std::integral_constant<int, 2> {};
template<>
struct Category<Type_E> : std::integral_constant<int, 2> {};
template<>
struct Category<Type_F> : std::integral_constant<int, 2> {};
template<class T>
void foo(std::integral_constant<int, 1>, T x)
{
// Category 1 types.
}
template<class T>
void foo(std::integral_constant<int, 2>, T x)
{
// Category 2 types.
}
template<class T>
void foo(T x)
{
foo(Category<T>(), x);
}
As an alternative to category selection via "traits", you can also consider CRTP (where the type carries the category as a base):
template<class Derived> class category1 {};
template<class Derived> class category2 {};
class A1: public category1<A1> { ..... };
class A2: public category2<A2> { ..... };
class B1: public category1<B1> { ..... };
class B2: public category2<B2> { ..... };
template<class T>void funcion_on1(category1<T>& st)
{
T& t = static_cast<T&>(st);
.....
}
template<class T>void funcion_on1(category2<T>& st)
{
T& t = static_cast<T&>(st);
.....
}
The advantage is to have a less polluted namespace.
I learned the following technique from R. Martinho Fernandes. The code shown below is written to illustrate the bare bones of the problem but you should refer to this blog post to get the full range of tricks to make it pretty.
You've already mentioned that you're running into problems because of signatures being identical. The trick is to make the types to be different.
Your second approach is close, but we can't use void as the resulting type of the std::enable_if<>.
Note that the following code does not compile, and specifying void for the std::enable_if<> does not change anything since the default is void anyway.
#include <iostream>
class A {};
class B {};
template <
typename T,
typename = typename std::enable_if<std::is_same<T, A>::value>::type>
void F(T) {
std::cout << "A" << std::endl;
}
template <
typename T,
typename = typename std::enable_if<std::is_same<T, B>::value>::type>
void F(T) {
std::cout << "B" << std::endl;
}
int main() {
F(A{});
F(B{});
}
The reason, as you already described is because the signatures are identical. Let's differentiate them.
#include <iostream>
class A {};
class B {};
template <
typename T,
typename std::enable_if<std::is_same<T, A>::value, int>::type = 0>
void F(T) {
std::cout << "A" << std::endl;
}
template <
typename T,
typename std::enable_if<std::is_same<T, B>::value, int>::type = 0>
void F(T) {
std::cout << "B" << std::endl;
}
int main() {
F(A{});
F(B{});
}
Prints:
A
B
We have now differentiated the types between the 2 functions because rather than the second template parameter being a type, it is now an int.
This approach is preferable to using std::enable_if<> in the return type for example since constructors don't have return types, the pattern wouldn't be applicable for those.
Notes: std::is_same<> is used with a single class to simplify the condition.
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}