Specification with keyword template in the generic programming [duplicate] - c++

This question already has answers here:
Where and why do I have to put the "template" and "typename" keywords?
(8 answers)
Closed 9 years ago.
#include <iostream>
namespace oo{
class A{
public:
template<typename T>
static T get_value(){return static_cast<T>(55);}
};
template <typename T=A>
class B{
public:
static double f(){return T::get_value<double>();}
};
}
int main(int argc, char *argv[])
{
using std::cout;
using std::endl;
cout << oo::B<oo::A>::f() << endl;
return 0;
}
Considering the example up here, it compiles with an error "type name is not allowed" which refers to "double" and arguments in "get_value()".
Someone has righted this wrong by rewriting the function f() as followed:
static double f(){return T::template get_value<double>(); }
Yet, I do not quite understand the use of "template" here. Could anyone explain that to me, please?
Thanks in advance for your comments.

The reason is how the compiler interpret that line, when you use templates, the syntax has more than one possible interpretation, take a look to the following :
static double f()
{
return T::get_value < double > ();
}
in your function, how you now that the T parameter passed to the B class has a function named get_value or a data member named get_value ? If the case is the second then you are using the operator lees-than between that member and double, and then between double and (). Well the first assumption of the compiler is these option, if you wat to tell him that this is a function with template (for the correct interpretation of "<") you need to put the keyword template

this is what's going on at runtime.
namespace oo{
class A{
public:
// template<typename T> // T replaced with <double> type.
static double get_value(){return static_cast<double>(55);}
};
//template <typename T=A> // T replaced with <oo::A> type.
class B{
public:
static double f(){return oo::A::get_value/*<double>*/();}
};
}
int main(int argc, char *argv[])
{
using std::cout;
using std::endl;
cout << oo::B::f() << endl;
return 0;
}
this line :
static double f(){return T::get_value();}
is correct and usually will be compiled without any errors(depend on witch compiler you're using), because the template declaration will be valid for the next scope.
template <class T>
class foo
{
//T will be valid in this scope.
};
this is not the case to implement template classes/functions, you usually want to do that in cases where you want to prevent the using of multiple overloading.

Related

Undefined class error when template class member uses class itself as template parameter

The code excerpt below is a minimal working example of an issue that I am struggling to understand involving C++ templates. As it is, the code compiles fine. If the lines outside of the main function that are commented out are commented back in, I receive the following compilation error relating to line 73 i.e. C<A> c(A<C<A>>(3.0));:
testing.cpp(61): error C2079: 'C<A>::b_' uses undefined class 'A<C<A>>'
testing.cpp(10): note: see reference to class template instantiation 'C<A>' being compiled
testing.cpp(73): note: see reference to class template instantiation 'A<C<A>>' being compiled
Line 69 i.e. C<A> c(A<C<A>::this_class>(3.0)); compiles in all cases.
#include <iostream>
#include <vector>
using namespace std;
template<class Z>
class A {
public:
// typedef typename Z::traits_type Traits;
A(double data = 2.0) : data_(data) {
cout << "Constructing A with data: " << data_ << endl;
}
double data() const {
return data_;
}
void setup(Z* z) {
z_ = z;
}
void doStuff() const {
// cout << "A's foo: " << Traits::foo() << endl;
cout << "Instance of Z's data_: " << z_->data_ << endl;
}
private:
double data_;
Z* z_;
};
//struct CTraits {
// static int foo() {
// return 1;
// }
//};
template<template <class> class B = A>
class C {
public:
typedef C<B> this_class;
// typedef CTraits traits_type;
C(const B<this_class>& b = B<this_class>()) : data_(4.0), b_(b) {
cout << "Constructing C using B with data: " << b_.data() << endl;
b_.setup(this);
}
void doStuff() const {
b_.doStuff();
}
private:
double data_;
friend class B<this_class>;
B<this_class> b_;
};
int main(int argc, char* argv[]) {
// The following line compiles regardless of whether all lines above that
// are commented are commented in or out.
// C<A> c(A<C<A>::this_class>(3.0));
// This will not compile if the lines above, outside of main, that are commented
// out are commented back in.
C<A> c(A<C<A>>(3.0));
return 0;
}
My question is, why does the line C<A> c(A<C<A>>(3.0)); cause a compilation error when the commented out lines above it, outside of main, are commented back in? In other words, what changes to cause the compilation to fail?
Additionally, why does the line C<A> c(A<C<A>::this_class>(3.0)); compile when C<A> c(A<C<A>>(3.0)); does not? In other words, what is special about using C<A>::this_class as the template parameter to A over just using C<A>?
I managed to reproduce your issue using clang++.
Let's start with a simpler example. Keep the class definitions you have, but instead use the following main:
int main(int argc, char* argv[]) {
A<C<A>> x(3.0);
}
This fails to compile---let's work out why (informally).
The compiler has to instantiate the class A<C<A>>. To do that, it plugs C<A> into A as the template parameter Z. Then it sees the line typedef typename Z::traits_type Traits, which requires it to instantiate Z, which is C<A>. When instantiating C<A>, it sets the template parameter B to A, so when it sees B<this_class> b_ it has to instantiate A<C<A>>. But this is the same class we were trying to instantiate at the beginning! This is why the compiler gives an error---it has an "incomplete type" because the compiler realizes it has started instantiating that type already, but hasn't finished yet.
This is the same reason why you get an error if you define:
class D {
D x;
};
Now for the second part of your question: why does using this_class fix the problem?
To understand that, consider this simpler example (again with the same class definitions as before):
int main(int argc, char* argv[]) {
typedef C<A>::traits_type y;
A<C<A>> x(3.0);
}
What's happening here is that the typedef statement requires the compiler to instantiate C<A> early. In doing so, it encouters the b_ variable as before and tries to instantiate A<C<A>>, which once again plugs C<A> into A as the template parameter Z. Then it sees the line typedef typename Z::traits_type Traits, but at this point it has already evaluated the typedef CTraits traits_type for C<A> and therefore continues without trying to instantiate C<A> again.
Causes
To summarize the above discussion, there are two causes for the behavior you're seeing. First, even though you just need C<A>::traits_type the compiler will try to instantiate the entire C<A>. Second, the compiler is OK with incomplete types when accessing C<A>::traits_type (Z<A>::traits_type), but not when instantiating the type itself as in A<C<A>> b_ (B<this_type> b_).
The reason why C<A> c(A<C<A>::this_class>(3.0)); works is that C<A>::this_class forces the compiler to instantiate C<A> early.
Workaround
One possible workaround for you is to explicitly instantiate the template you need ahead of time, to prevent the loop:
template class C<A>;
int main(int argc, char* argv[]) {
C<A> c(A<C<A>>(3.0));
}

How to pretty print the name of a template parameter at compile time

The question is rather simple: how to pretty print the name of a template parameter in a C++ class and assign it to a class variable at compile time ?
It seems that both typeinfo (typeid) and boost::typeindex must be evaluated at runtime or as least some part of them. This apparently does not allow the compiler to completely solve a constexpr containing a call to one of this function.
template<typename T>
class X
{
public:
static const char * name = /* SOME C++ code transforming T in a string (either std::string or char */
};
What am I missing ?
Is it only possible to generate a name at runtime ? In that case, does I really need an instantiated object ? It doesn't seem right to me, because the following perfectly work without any instance:
#include <iostream>
#include <string>
#include <boost/type_index.hpp>
using namespace std;
template<class T>
class X
{
public:
static std::string name()
{
return boost::typeindex::type_id<T>().pretty_name();
}
};
struct foobar {};
int main()
{
cout << X<int>::name() << endl;
cout << X<foobar>::name()<< endl;
}
So instead of having name() as a class method, I'd like to have it as a class variable.
I think, it is possible to use custom Type Traits. Please see the next example:
#include <iostream>
#include <string>
using namespace std;
//Using stub type traits
template <class T>
struct TypeTraits;
//your TypeTraits for specific types...
template<>
struct TypeTraits<int>
{
constexpr static const char *name = "int";
};
template<class T>
class X
{
public:
constexpr static const char * name = TypeTraits<T>::name;
};
struct foobar {};
//TypeTraits for custom foobar
template<>
struct TypeTraits<foobar>
{
constexpr static const char *name = "foobar";
};
int main()
{
//Now you can use static member here
cout << X<int>::name << endl;
cout << X<foobar>::name<< endl;
}
Also TypeTraits can be used (and expanded) for other purposes.

Access static member of template class

I just want to access the static member of a template class. I know there are many posts here on how to initialize it, but my problem is printing its value.
#include<iostream>
using namespace std;
template<typename T>
class X
{
static int i;
};
//There are answers everywhere on this site to initialize it
template<typename T>
int X<T>::i = 5;
//But Please help me to access it
int main()
{
X<int> x;
//Problem below I just want to access it
cout << endl << X<int>::i << endl;
return 0;
}
Another case where the compiler error message contains the answer. E.g. gcc says
main.cpp:13:5: error: 'int X::i' is private
and of course you cannot access private fields from outside the class. Make it public instead.

Get type of class from a static method [duplicate]

This question already has answers here:
Can I implement an autonomous `self` member type in C++?
(14 answers)
Closed 8 years ago.
I have a template class with a static method, ideally I would like to add to this method something like this std::cout << decltype(this) << std::endl; but this doesn't compile since I can not use this inside a static method. I found a working example here (not sure I can print decltype output) but it also uses this so I can not use it inside the static method. I was forced to use it inside the constructor, but I didn't give up yet. Does anyone has an idea how to print the class type inside a static method?
Did you mean something like:
#include <iostream>
#include <typeinfo>
template <typename T>
class C
{
public:
static void print()
{
std::cout << typeid(C).name() << std::endl;
}
};
int main() {
C<int>::print();
C<char>::print();
return 0;
}

Weird behaviour of Koenig Lookup

consider the following program:
namespace NS2 {
class base { };
template<typename T>
int size(T& t) {
std::cout << "size NS2 called!" << std::endl;
return sizeof(t);
}
};
namespace NS1 {
class X : NS2::base { };
}
namespace NS3 {
template<typename T>
int size(T& t) {
std::cout << "size NS3 called!" << std::endl;
return sizeof(t) + 1;
}
template<typename T>
class tmpl
{
public:
void operator()() { size(*this); }
};
};
int main() +{
NS3::tmpl<NS1::X> t;
t();
return 0;
}
My compiler (gcc 4.3.3) does not compile the program because the call to size is ambigous. The namespace NS2 seems to be added to the set of associate namespaces for the size call in the class tmpl. Even after reading the section about Koenig Lookup in the ISI Standard I am not sure if this behaviour is standard conform. Is it?
Does any one know a way to work around this behaviour without qualifying the size call with the NS3 prefix?
Thanks in advance!
Template arguments and base classes both affect ADL, so I think GCC is correct, here: NS3 comes from the current scope, NS1 from the X template argument, and NS2 from the base class of the template argument.
You have to disambiguate somehow; I'd suggest renaming one or more of the functions, if feasible, or perhaps use SFINAE to disambiguate the functions.
(Similar Situation: Note that boost::noncopyable is actually "typedef noncopyable_::noncopyable noncopyable;" so that the boost namespace doesn't get added to the ADL set of types that derive from it.)