Template specialization and derived classes in C++ - c++

I have this simple code:
class A{};
class B : public A{};
class C : public B{};
class Test
{
public:
template<typename T>
void f(T&){printf("template\n");}
void f(A&){printf("specialization\n");}
};
int main()
{
A a;
B b;
C c;
Test test;
test.f(a);
test.f(b);
test.f(c);
}
When I run it(VS2010) I have this output:
specialization
template
template
Is it possible to make the calls with A-derived classes to use specialization?

Yes, it is possible, but you have to change your code a bit.
First of all, to be technical, the second function f() is not a specialization of the template function, but an overload. When resolving overload, the template version is chosen for all arguments whose type is not A, because it is a perfect match: T is deduced to be equal to the type of the argument, so when calling f(b), for instance, after type deduction the compiler will have to choose between the following two overloads:
void f(B&){printf("template\n");}
void f(A&){printf("specialization\n");}
Of course, the first one is a better match.
Now if you want the second version to be selected when the function is invoked with an argument which is a subclass of A, you have to use some SFINAE technique to prevent the function template from being correctly instantiated when the type T is deduced to be a subclass of A.
You can use std::enable_if in combination with the std::is_base_of type traits to achieve that.
// This will get instantiated only for those T which are not derived from A
template<typename T,
typename enable_if<
!is_base_of<A, T>::value
>::type* = nullptr
>
void f(T&) { cout << "template" << endl; }
Here is how you would use it in a complete program:
#include <type_traits>
#include <iostream>
using namespace std;
class A{};
class B : public A{};
class C : public B{};
class D {};
class Test
{
public:
template<typename T,
typename enable_if<!is_base_of<A, T>::value>::type* = nullptr
>
void f(T&) { cout << ("template\n"); }
void f(A&){ cout << ("non-template\n");}
};
int main()
{
A a;
B b;
C c;
D d;
float f;
Test test;
test.f(a); // Will print "non-template"
test.f(b); // Will print "non-template"
test.f(c); // Will print "non-template"
test.f(d); // Will print "template"
test.f(f); // Will print "template"
}
EDIT:
If you are working with a compiler which is not fully compliant with C++11 (and therefore does not support default template arguments on function templates), you might want to change the definition of your template overload of f() as follows:
template<typename T>
typename enable_if<!is_base_of<A, T>::value, void>::type
f(T&) { cout << ("template\n"); }
The behavior of the program will be identical. Note that if the return type of f() is void, you can omit the second argument to the enable_if class template.

Related

Template specialization for the base template type for future derived types

I have a class that works as wrapper for some primitives or custom types. I want to write explicit specialization for custom template type.
My code that reproduces the problem:
template < class T >
struct A {
void func() { std::cout << "base\n"; }
};
template <>
struct A<int> {};
template < class T, class CRTP >
struct BaseCrtp {
void someFunc() {
CRTP::someStaticFunc();
}
};
struct DerrType : BaseCrtp<int, DerrType> {
static void someStaticFunc() {}
};
template < class T, class CRTP >
struct A< BaseCrtp<T, CRTP> > {
void func() { std::cout << "sometype\n"; }
};
int main() {
A<DerrType> a;
a.func(); // print: "base". should be: "sometype"
return 0;
}
A<DerrType> use default function, not a specialization. How can I make specialization for these set of classes?
I will have a lot of types like DerrType, and I want to make common behavior for all of them.
DerrType and others will be used as curiously recurring template pattern
Not sure I fully understood what you want, but maybe something like this:
template<typename T>
concept DerivedFromBaseCrtp = requires(T& t) {
[]<typename U, typename CRTP>(BaseCrtp<U, CRTP>&){}(t);
};
template < DerivedFromBaseCrtp T >
struct A<T> {
void func() { std::cout << "sometype\n"; }
};
The concept basically checks whether T is equal to or is publicly inherited (directly or indirectly) from some specialization of BaseCrtp. Otherwise the call to the lambda would be ill-formed. Template argument deduction only succeeds in the call if the argument and parameter type match exactly or the argument has a derived type of the parameter. If the class is inherited non-publicly, the reference in the call can't bind to the parameter.
The concept will however fail if the type is inherited from multiple BaseCrtp specializations, in which case template argument deduction on the call will not be able to choose between the multiple choices.
Alternatively you can also use the stricter concept
template<typename T>
concept CrtpDerivedFromBaseCrtp = requires(T& t) {
[]<typename U>(BaseCrtp<U, T>&){}(t);
};
which will also require that the type T is actually using the CRTP pattern on BaseCrtp (directly or through a some base class between BaseCrtp and T). Again, this will fail if T is inherited multiple times from some BaseCrtp<U, T> specialization, although it will ignore specializations with a type other than T in the second position.
For another alternative you might want to check that T is derived from some type X such that X is derived from BaseCrtp<U, X> for some U (meaning that X uses the CRTP pattern correctly). That could be done using this variation:
template <typename T>
concept CrtpDerivedFromBaseCrtp =
requires(T& t) {
[]<typename U, typename CRTP>(BaseCrtp<U, CRTP>&)
requires(std::is_base_of_v<CRTP, T> &&
std::is_base_of_v<BaseCrtp<U, CRTP>, CRTP>)
{}
(t);
};
Again, this fails if T is derived from multiple BaseCrtp specializations, directly or indirectly.

Inner template classes inheritance

I have the following code: https://gist.github.com/PatrikValkovic/50329975f86e0328ff1f85fda17a23f3, live example here: http://cpp.sh/675a3.
In short, I have class A with inner class B<U> and class D that should inherit from the B<U>. The code works when the class D is declared within class A (as commented). However, when I move the declaration outside of the class A (as in the example), the compiler complains, that A<T>::B<U> is not a type. What is wrong about the syntax?
// Example program
#include <iostream>
#include <string>
using namespace std;
template<typename T>
class A
{
public:
template<typename U>
class B;
/*
class D : public B<int>
{
public:
void method2() {
cout << "Method 2" << endl;
this->method1();
}
};
*/
class D;
};
template<typename T>
template<typename U>
class A<T>::B
{
public:
void method1() {
T x;
cout << "Method 1: " << x << endl;
}
};
template<typename T>
class A<T>::D : public A<T>::B<int>
{
public:
void method2() {
cout << "Method 2" << endl;
this->method1();
}
};
int main()
{
A<int>::D b;
b.method2();
}
This is one of those really weird edge cases in the C++ language that has a unusual fix. The issue is here:
template<typename T>
class A<T>::D : public A<T>::B<int>
^^^^^^^^^^^^
The problem is that you are trying to use the template class B, which is a dependent name inside of A (that is, B is a template nested inside another type that depends on a template argument, here, T). By default, C++ won't treat dependent names as being names of types or names of templates, and you have to explicitly tell the compiler "yes, this is the name of a template" by using the template keyword in an unusual way:
template<typename T>
class A<T>::D : public A<T>::template B<int>
^^^^^^^^
This tells C++ "inside of A<T>, you're going to find a template type named B. Please use that template with argument int."
This is similar to how you have to use the typename keyword with dependent types - it tells the compiler "yes, this is the name of a type." Here, the template keyword tells the compiler "yes, this is the name of a template."

Accessing a member type of an incomplete type

What is the workaround to get this to compile?
#include <iostream>
template <typename Derived>
struct CRTP {
void foo (const typename Derived::type& a) {std::cout << a << '\n';}
};
struct A : CRTP<A> {
using type = int;
};
struct B : CRTP<B> {
using type = std::string;
};
// etc...
int main() {
A a;
a.foo(5);
}
This will not compile, because at the time of instantiation of CRTP<A>, A isn't a complete class yet, so A::type cannot be accessed. But what is the workaround? I need this type of design so that the foo function can be used generically for many different classes.
A somewhat crazier alternative is to defer evaluation until an attempt is made to call foo, by which point Derived would be complete. This requires making it a template.
template <typename Derived>
struct CRTP {
template<class T = Derived>
void foo (const typename T::type& a) {std::cout << a << '\n';}
};
It is trivial to block calling foo with a type that isn't Derived, if desired, via a static_assert.
I'm pretty sure you can't use the CRTP on a 'using' case. You can use it for methods and members, but not things like types. When using templates though, having types as template parameters is what it is so useful for, so why not do
template <typename Derived, typename Type>
....
Which will work perfectly fine.

Correct way to define a covariant template function in C++

What is the best and most correct way to define a template function whose argument's type is required to be a subclass of a certain base class?
Here is what I have:
class A {};
class B : public A {};
class C {};
template <typename T>
int foo(T& x) // NB: need a solution that allows a return value
{
A& dummy = x; // require T to be a subclass of A, else SFINAE
return 1;
}
//int foo(C&) { return 2; }
int main()
{
B b;
C c;
std::cout << foo(b) << "\n";
std::cout << foo(c) << "\n"; // should fail unless foo(C&) is defined
}
Is the above correct? I don't like it because it doesn't express intent. I would prefer something that read more like the following bogus code:
template <class A T>
void foo(T& x) {}
Maybe enable_if can be used somehow?
(Background: In my production code the functions are operators. I need them to be templates for metaprogramming reasons (to deduce the compile time type of T). But I want to restrict them to only match subclasses of A.)
Update #1: In a related question on Template Constraints C++ The following is given:
static_assert(std::is_base_of<A, T>::value, "T must be a sublass of A");
This captures the intent better than A& dummy = x; however it suffers from the same problem that if void foo(C&) { } is commented out, foo<T> still gets specialized for the call to foo(c) and then the static_assert fails. Whereas I would like for the compiler to not even try to specialize foo<T> for cases where the parameter is not a subclass of A.
Update #2: Based on the accepted answer here: Why does enable_if_t in template arguments complains about redefinitions? the following code appears to be close, however it is C++14 specific. I would like a solution portable to current standards.
template <typename T, std::enable_if_t<std::is_base_of<A, T>::value>* = nullptr>
void foo(T& x)
{
}
The advantage of the above is that when void foo(C&) is defined, the compiler gives the correct error: "error: no matching function for call to 'foo(C&)'".
Depends on the check you actually want to do.
To check for a public, unambiguous base, use is_convertible on pointers:
template <class T>
auto foo(T& x) -> std::enable_if_t<std::is_convertible<T*, A*>{}/*, void*/> {
// stuff
}
To check for any base whatsoever, public, protected or private, ambiguous or unambiguous, use is_base_of:
template <class T>
auto foo(T& x) -> std::enable_if_t<std::is_base_of<A, T>{}/*, void*/> {
// stuff
}
The following is another way to do it, based on T.C.'s answer, and the accepted answer here: (Why does enable_if_t in template arguments complains about redefinitions?):
#include <type_traits>
#include <iostream>
// Provide enable_if_t in C++11
#if __cplusplus <= 201103L
namespace std {
template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
}
#endif
class A {};
class B : public A {};
class C {};
template <typename T, std::enable_if_t<std::is_convertible<T*, A*>::value>* = nullptr>
int foo(T& x)
{
return 1;
}
//int foo(C& x) { return 2; }
int main()
{
B b;
C c;
std::cout << foo(b) << "\n";
std::cout << foo(c) << "\n"; // should fail unless foo(C&) is defined
}
This correctly ignores the templated foo when int foo(C& x) is undefined, and therefore gives the expected (desired) compiler error for the foo(c) line:
error: no matching function for call to 'foo'

Template specialization within class definition

I wonder whether it is possible to put the whole code of such a class inside the class (kind of as in Java). I'm doing this for some piece of code, instead of having to search for each function, I'd rather have the whole class on a single sheet of paper (yes, I do print them, I tend to like paper these days).
#include <iostream>
template <class V> class A {
public:
A();
};
template <class V> A<V>::A() {
std::cout<<"Generic"<<std::endl;
}
template <> A<bool>::A() {
std::cout<<"bool"<<std::endl;
}
int main(int argc, char** argv) {
A<int> a;
A<bool> b;
}
Now is it possible to get something along those lines ?
#include <iostream>
template <class V> class A {
public:
A() {
std::cout<<"Generic"<<std::endl;
};
/* somethig specifying specialization for bool */ A() {
std::cout<<"bool"<<std::endl;
}
};
int main(int argc, char** argv) {
A<int> a;
A<bool> b;
}
Is this possible at all ?
Yes, it is possible to have everything in a single class definition without specializations, using std::enable_if to choose the appropriate constructor like this:
template <bool C, typename T = void>
using only_if = typename std::enable_if <C, T>::type;
template <typename A, typename B>
using eq = typename std::is_same <A, B>::type;
template <class V> class A {
public:
template <typename D = int, only_if <!eq <V, bool>{}, D> = 0>
A() { std::cout<<"Generic"<<std::endl; };
template <typename D = int, only_if <eq <V, bool>{}, D> = 0>
A() { std::cout<<"bool"<<std::endl; }
};
where template aliases only_if and eq are just for brevity.
Template parameter D is dummy. Usually we apply enable_if on a template parameter, a function argument, or a return type. A non-template default constructor is a unique exception having nothing of the above, hence the dummy.
This approach is maybe an overkill for this simple example, where a template specialization may be simpler. But a class of 30 lines of code that needs a specialization like that for just one constructor will be definitely simpler this way rather than duplicating all code for the entire class specialization. One may argue that in this case the code may be refactored using a base class that contains only what needs to be specialized. However:
There are also cases where you don't want to choose between two constructor versions, but only to enable or disable a single version according to a type predicate, e.g. whether a type is std::default_constructible or not.
Or, you may need to decide whether a constructor is declared explicit or not, again depending on a type predicate (so, provide an explicit and a non-explicit version).
In such cases, enable_if is very convenient.
Check here an example of a very generic tuple implementation with five constructors, all using enable_if, and one (the default) using a dummy template parameter. The remaining four are for the combinations of explicit vs. non-explicit and element-list vs other-tuple.
Yes.
It is completely possible though the specialization must be done in other template.
#include <iostream>
template <class V> class A {
public:
A() {
std::cout<<"Generic"<<std::endl;
};
};
template <> class A<bool>
{
public:
A() { std::cout << "Bool specialization" << endl; }
};
int main(int argc, char** argv) {
A<int> a;
A<bool> b;
}