C++ template class with default parameters, and probably metaprogramming - c++

I went into trouble understanding the following codes:
#include <iostream>
using namespace std;
template <class PixType, bool B = PixType::is>
class Test {
public:
void print() {
cout << "PixType B=false" <<endl;
}
};
template <class PixType>
class Test<PixType,true> {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
class PT {
public:
static const bool is = false; // here is the magic
};
int main() {
Test<PT> t;
t.print();
}
I have 4 questions:
What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Why can two same classes(both are named Test) exist at the same time.
In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
I am really new to these template stuff, and got really confused by these lines of codes. And I don't know how to search for this trick. In most articles about C++ templating, they just talk about some basic ideas and usages about template.
Any help will be greatly appreciated.

Point 1 What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Response The first one is the main class template definition. The second one is a specialization of the class template where the second parameter of the template is true.
If you didn't have the second one, the first one will be used regardless of whether the second parameter of the template is true or false.
Point 2 Why can two same classes(both are named Test) exist at the same time.
Response In your case, the second one is a specialization of the first one. When you use:
Test<int, true> a;
The compiler knows to use the specialization to generate code for Test<int, true>. When you use:
Test<int, false> b;
The compiler know to use the first one to generate code for Test<int, false>.
Point 3 In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
Response As I explained above, when the second parameter is true, the compiler uses the second class template. Otherwise, it uses the first class template. I hope there is no confusion about that any more.
Point 4 I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
Response
Class templates can only be specialized, they cannot be overloaded.
template <typename A, typename B> class C1 {};
template <typename A> class C1 {};
The above is not supported by the language.
template <typename A, typename B> class C1 {};
template <typename A> class C1<A, A*> {};
The above is supported by the language. The second class template is a specialization of the first class template.
What you are trying to do is provide a default value for the second parameter but the name used to define the class template is same. The second one is a different class template not a specialization of the first class template.

Related

C++: providing a class function in templated class on existence of named member in its templated type?

I am trying to do the following: a templated class should provide some functions dependend on whether or not the type it has been templated with contains a member variable with a given name. As example the following pseudocode which should provide "printid()" only when templated struct/class has a member called "id":
#include <iostream>
#include <type_traits>
struct A { int id; };
struct B { };
template<typename T>
class foo
{
T myvar;
public:
#if exists T.id (or the alternative: #if exists myvar.id)
printid() { std::cout << "I have element id."; }
#endif
};
int main(){
foo<A> ok;
ok.printid(); // should compile and execute
foo<B> nok;
nok.printid(); // should not compile
return 0;
}
Digging around SFINAE, traits, std::enable_if and StackOverflow, I think it can be done ... somehow. But I somehow fail to combine enable_if with the the following snippet from the question How to detect whether there is a specific member variable in class?:
template<typename T, typename = void>
struct has_id : std::false_type { };
template<typename T>
struct has_id<T, decltype(std::declval<T>().id, void())> : std::true_type { };
Any help appreciated.
Yep, it's possible. Here's an example:
template<typename T>
class foo
{
T myvar;
public:
template <class _T = T,
class = typename std::enable_if<
!std::is_function<decltype(_T::id)>::value>
::type>
void printid() { std::cout << "I have element id."; }
};
Specifically, note how we're "taking in" T as _T in order to not force a constraint on the class template parameter (which would make the class itself un-compileable). Instead, we're creating a new, independent template member function, which doesn't force anything on T itself—it just "happens to" use it as a default argument. That's the key part.

Avoid angle brackets in default template

If I have a template class with a default template type, I have to write the template angle brackets. Is it somehow possible to avoid this?
Example:
template <typename T=int>
class tt {
public:
T get() { return 5; }
};
...
tt<> t; // how to avoid <>
std::cout << t.get() << std::endl;
Until now i've did this by a separate namespace and redeclaring the class:
namespace detail_ {
template <typename T=int>
class tt {
public:
T get() { return 5; }
};
}
class tt : public detail_::tt {}
...
tt t;
std::cout << t.get() << std::endl;
The problem is, if I want to use the class with an other type I have to go over namespace detail_. Is there another solution, which I didn't see yet.
... if I want to use the class ...
This is a common source of confusion. A class template is not a class, but a template from which classes are generated. The angle brackets is what tells the compiler that you want to generate a class out of the class template with the given template arguments, without the angle brackets what you have is a template.
template <typename T = int>
struct TemplateClass { /*...*/ };
template <template <typename> class T>
void f() {
T<int> t; // ...
}
template <typename T>
void g() {
T t; // ...
}
f<TemplateClass>(); // Accepts a template with a single type argument
g<TemplateClass<> >(); // Accepts a type, that can be generated out of the template
The language does not allow the coexistence of a template and a type with the same name in the same namespace, so the answer is that it cannot be done. You can create a type alias but you will have to give it a different name.
You can use typedef...
typedef tt<> tt_;
And then simply use tt_.
Since C++17, because of class template argument deduction, things have changed.
tt and tt<> are not the same thing: types and class templates were different and continue to be treated differently.
Anyway in simple scenarios like the one in your example, C++17 assumes what you mean and the <> aren't needed anymore.
Further details:
Template default arguments (specifically https://stackoverflow.com/a/50970942/3235496);
Why is <> required when specifying a template class which has defaults for all its template parameters?

How to test for presence of an inner class in a class via SFINAE?

I'm trying to have a different template specialization for classes which have an inner class with a particular name present. I've taken a clue from here and tried the following:
#include <iostream>
template< typename T, typename Check = void > struct HasXYZ
{ static const bool value = false; };
template< typename T > struct HasXYZ< T, typename T::XYZ >
{ static const bool value = true; };
struct Foo
{
class XYZ {};
};
struct FooWithTypedef
{
typedef void XYZ;
};
int main()
{
// The following line prints 1, as expected
std::cout << HasXYZ< FooWithTypedef >::value << std::endl;
// The following line prints 0. Why?
std::cout << HasXYZ< Foo >::value << std::endl;
return 0;
}
As you can see, if I test for a typedef-defined type in FooWithTypedef, it works. However, it does not work if the type is a genuine inner class. It also only works when the typedef-ed type in FooWithTypedef matches the default value of the second argument in the initial template declaration (which is void in my example). Could one explain what is going on here? How does the specialization process work here?
Answer to the initial question
The template specialization you defined here:
template <typename T> struct HasXYZ <T,typename T::XYZ>
{ static const bool value = true; };
will take effect when somebody uses the data type HasXYZ<A,A::XYZ> for some data type A.
Note that, whatever A is, A::XYZ is a data type totally independent of A. Inner classes are data types in their own right. When you use A as the first template argument, there is absolutely no reason for the compiler to assume that you want to use something called A:XYZ as the second argument, even if an inner class of that name exists, and even if doing so would lead the compiler to a template specialization that matches the template arguments exactly. Template specializations are found based on the template arguments provided by the coder, not based on further possible template arguments.
Hence when you use HasXYZ<Foo>, it falls back to using the default template argument void for the second parameter.
Needless to say that if you were to use HasXYZ<Foo,Foo:XYZ> explicitly, you'd get the expected output. But that obviously is not what you intended.
I am afraid the only way to get what you need is std::enable_if (or something that works in a similar way).
Answer to the additional question (after update)
Consider the simplification below:
template <typename T, typename Check = void>
struct A
{ static const bool value = false; };
template <typename T>
struct A<T,void>
{ static const bool value = true; };
The primary definition specifies a default argument of void for the second template parameter. But the specialization (second definition above) defines what class A actually looks like if the second template parameter really is void.
What this means is that if you use, say, A<int> in your code, the default argument will be supplemented so you get A<int,void>, and then the compiler finds the most fitting template specialization, which is the second one above.
So, while default template arguments are defined as part of the primary template declaration, making use of them does not imply that the primary template definition is used. This is basically because default template arguments are part of the template declaration, not the template definition (*).
This why in your example, when typedef void XYZ is included in FooWithTypedef, the second template parameter defaults to void and then the most fitting specialization is found. This works even if in the template specialization the second argument is defined as T::XYZ instead of void. If these are the same at the time of evaluation, the template specialization will be selected (§14.4 "Type equivalence").
(*) I didn't find a statement in the Standard that actually says it so clearly. But there is §14.1/10, which describes the case where you have multiple declarations (but only one primary definition) of a template:
(§14.1/10) The set of default template-arguments available for use with a template declaration or definition is obtained by merging the default arguments from the definition (if in scope) and all declarations in scope in the same way default function arguments are (8.3.6). [ Example:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
].
This suggests that the mechanism behind default template arguments is independent of that used to identify the most fitting specialization of the template.
In addition, there are two existing SO posts that refer to this mechanism as well:
This reply to Template specialization to use default type if class member typedef does not exist
Default values of template parameters in the class template specializations
Here is another version that detects the presence of the inner class :
#include <iostream>
template< typename T >
struct HasXYZ
{
typedef char yes;
typedef struct{ char d[2]; } no;
template<typename T1>
static yes test( typename T1::XYZ * );
template<typename T1>
static no test(...);
static const bool value = ( sizeof( test<T>(0) ) == sizeof( yes ) );
};
struct Foo
{
class XYZ {};
};
struct Bar
{
class ABC {};
};
int main()
{
std::cout << std::boolalpha << HasXYZ< Foo >::value << std::endl;
std::cout << std::boolalpha << HasXYZ< Bar >::value << std::endl;
}
A::XYZ would need to void to have the partial specialization selected, which can never be the case for a class type. One way to make it work is using a fake dependant void typename:
template<class T>
struct void_{ typedef void type; };
template<class T, class = void>
struct has_XYZ{ static bool const value = false; };
template<class T>
struct has_XYZ<T, typename void_<typename T::XYZ>::type>{
static bool const value = true;
};
For an explanation on how this works, see this question.

How to count the number of CRTP subclasses of a template class?

Does anyone know of a method to use CRTP to count the number of subclasses of an object?
Suppose we had a setup similar to the following one:
template <typename T>
class Object
{
....
};
const unsigned int ObjectSubClassCount = ...;
class Subobject : public Object<SubObject>
{
....
};
class Second : public Object<Second>
{
....
};
and so on, such that, using TMP, we might have a constant (ObjectSubClassCount) that represents the total number of subclasses?
Does anyone know a way to do this?
Edit: I am wanting to use the result as a template parameter later on, so I need it to be done with TMP...
Without the requirement to use the result as a template parameter later I would try it doing like this:
// Class which increments a given counter at instanciation
struct Increment {
Increment(std::size_t& counter)
{
counter++;
}
};
// This is your template base
template <typename T>
class Object
{
private:
// For every instanciation of the template (which is done for a subclass)
// the class counter should get incremented
static Increment incrementCounter;
};
// This is the global object counter
static std::size_t classCounter;
// Static Member Variable
template<typename T>
Object<T>::incrementCounter(classCounter);
Haven't tried it but should do. To have the result available as a template parameter again (MPL) I don't have enough experience in MPL but I doubt this is possible.
Ok, so I've come upon a... somewhat acceptable answer.
I figured that it would not work out if the subclasses had absolutely not knowledge of eachother (I mean, we're talking somewhat functional programming...).
Here's a solution for this. It's definitely not the solution I'd wish for; however, it is a start. I've forced all objects to use a form of CRTP, but one that uses more of a linked list format. In this way, our subclasses must be derived from an Object<> templated from:
A: itself
and B: the most recent previously defined subclass
here is my code for this (I use a template from <type_traits> once, just a note)
template <typename T> //SFINAE check for the existance of subclasscount static member
struct has_subclasscount
{
template <typename U>
static typename std::enable_if<sizeof(U::subclasscount) != 0, int>::type test(int);
template <typename U>
static char test(...);
static const bool result = (sizeof(test<T>(0)) == sizeof(int))?(true):(false);
};
template <bool res, typename T>
struct return_subclasscount //the value to return is 0 if false
{
static const int result = 0;
};
template <typename T>
struct return_subclasscount<true, T> //returns subclasscount only if the first parameter is true
{
static const int result = T::subclasscount;
};
template <typename T> //combines return_subclasscount and has_subclasscount
struct get_subclasscount
{
static const int result = return_subclasscount<has_subclasscount<T>::result, T>::result;
};
template <typename This, typename Prev>
class Object
{
public:
static const int subclasscount = 1 + get_subclasscount<Prev>::result; //the subclass count
};
class sub1 : public Object<sub1, int>
{
};
class sub2 : public Object<sub2, sub1>
{
};
class sub3 : public Object<sub3, sub2>
{
};
These last 3 empty classes are the subclasses that we're counting. This is our header file.
In our main .cpp file, we have:
int main() {
std::cout << sub3::subclasscount;
char c;
std::cin >> c;
}
Running it, we get a simple output of:
3
Which confirms that it has worked.
Now, some of the downsides to this solution is:
We must know what our last defined subclass was, before we add on.
We must keep up with anywhere we use the subclass counter, always modifying it to be from the last subclass in the list (this can be averted by using a consistant "endoflist" subclass, which would need to be maintained instead)
Upsides, though, include the fact that we do not need to upkeep any of our previously defined subclasses. However, I consider this answer more of a "starting point" than a "final solution"; perhaps something that can be expanded upon?
(also, this can easily be abused to make a form of tree structure, where subclasscount would actually represent the depth of any given node in the tree)
Anyone have any ideas from here?

Specialized function in non specialised Template class

Please refer to the below code
Specialized function in non specialized Template class
Is it possible to write a specialized function foo, for non specialized template class MyClass [Line Number 7] ? If yes, then, what is the syntax for the same.
Regards,
Atul
This can be done if you create a full specialization of the class template. Just refer to the answer in this question: If I want to specialise just one method in a template, how do I do it?
Otherwise if you want to have a given function with the same signature have two different behaviors depending on the instantiated version of the class, and that instantiation is a partial specialization of the template class, you will have to make a separate specialization of the template class.
Keep in mind that if you want to avoid redundant code in this second case, you can always create a base template class that will have the functionality that will not change, and then create derived template classes that will contain the unique functionality necessary for each partial specialization.
Look at my example below, I have tried answer your question (if I guessed right) in the simplest code possible by me:
#include <iostream>
using namespace std;
template<typename T>
class Some
{
public:
template<typename U> void foo(U val);
};
template<typename T>
template<typename U>
void Some<T>::foo(U val)
{
cout << "Non specialized" << endl;
}
template<>
template<>
void Some<char>::foo(char val)
{
cout << "Char specialized" << endl;
}
int main()
{
Some<int> t1;
t1.foo(5);
Some<char> t2;
t2.foo('c');
return 0;
}
The important thing to note here is that "You cannot specialize your class and function Independently" i.e you have to specialize both at the same time as done in the example.
Also, with this you lose the opportunity to specialize your class for that data type "char" in this case. (Need to confirm on this).
UPDATE :: Confirmed on point 2.
If you wanted to specialize MyClass< bool >::Foo, it would look like this:
template <>
void MyClass<bool>::Foo(bool A)
{
// code goes here
}
If you are asking that,
(1) you want a function Foo() which doesn't take any argument and
returns void inside MyClass
(2) This Foo() should be exclusive to the MyClass when the
template type is bool, i.e. only for MyClass<bool>
then here is the way:
template<class Precision>
class MyClass {
...
public:
...
void Foo (); // don't implement here
};
...
template<>
void MyClass<bool>::Foo () // implementing only for 'MyClass<bool>'
{ // invoking for other 'MyClass<>' will result in compiler error
...
}