Could you please advise why I am getting the error in the code below?
error: cannot define member function ‘Test<int>::Printer::Print’ within ‘Test<int>’
I am using gcc version 8.1.1 and compile the code as g++ -std=c++11.
Although, if I move the definition of function Print under the definition of struct Printer (i.e. making it inline implicitly), the compiler does not produce any error.
#include <iostream>
template <typename Type>
struct TestBase {
struct Printer {
template <typename T>
void Print(const T& t) {
std::cout << t << std::endl;
}
};
};
template <typename Type>
struct Test;
template<>
struct Test<int> : public TestBase<int> {
struct Printer : public TestBase<int>::Printer {
template <typename T>
void Print(int i, const T& t);
};
template <typename T>
void Printer::Print(int i, const T& t) {
std::cout << i << t << std::endl;
}
};
int main() {
Test<int> t;
}
UPDATE:
Brian pointed out the exact reason why it is the case: "... A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition..."
Brian not only answered the main question that started this topic but also an additional question that I asked in the comment to the accepted answer of him.
[class.mfct]/1, emphasis mine:
... A member function definition that appears outside of the class definition shall appear in a namespace scope enclosing the class definition. ...
An enclosing class scope is thus not an allowed location for the definition.
Related
This has been driving me crazy for the past couple hours, and I cannot seem to get around this problem. I have distilled the problem down to these 60 lines of code (including a main function).
#include <iostream>
namespace n1 {
// the general definition
template <class X, class Y> void f(X&, const Y&)
{
std::cout << "general template definition.\n";
}
} // namespace n1
namespace n2 {
// CRTP
template <class Derived> class A
{
int data;
// partial function template specialization for n1::f, and declare
// it a friend too, so that it may access the data attribute of A
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
}; // class A
} // namespace n2
namespace n1 {
// implementation for this particular function template specialization
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
{
std::cout << "partial template specialization: " << a.data << "\n";
}
} // namespace n1
namespace n2 {
// Another class!
class B : public A<B>
{
}; // class B
} // namespace n2
namespace n1 {
// --------------------
// tricky part is here!
// --------------------
template <class Y> void f(n2::B& b, const Y& y)
{
// FAIL! not a friend! How?
f(static_cast<n2::A<n2::B>&>(b), y);
}
} // namespace n1
int main()
{
n2::B b;
int x;
n1::f(b, x); // should print "partial template specialization"
return 0;
}
So, what I "want" is to have the compiler select my function template specialization of n1::f whenever it is invoked with a concrete subclass of A<Derived>. In order to make sure that the compiler favors my specialization, I need to supply, for every subclass (B in this case), also a template specialization for n1::f that simply delegates the call. When that happens, I expect the data member variable of A<Derived> to be accessible to n1::f, because I declare n1::f to be a friend of A<Derived>. However, GCC complains that A<Derived>::data is private and inaccessible, see this snippet on Coliru.
Is this construction possible? If so, how can I get around the compiler complaining that A<Derived>::data is not accessible? (Making it public is not an option).
Your class definition must look like this:
template <class Derived> class A
{
int data;
template <class D, class Y> friend void n1::f(A<D>& a, const Y& y);
};
In fact, function declaration is:
template <class Derived, class Y> void f(n2::A<Derived>& a, const Y& y)
While your friend declaration is:
template <class Y> friend void n1::f(A<Derived>& a, const Y& y);
In this case, they are different beasts and that's why you receive that error. As you can see, template parameters lists are different. That's not a declaration of a function with a separated definition. They are two different function templates, one declared and the other one both declared and defined.
In other terms, in your code you are declaring a friend function but you never define it. On the other side, you introduced a free function template that cannot read the data member for it's private and the function isn't a friend one of A<Derived>.
See it running on wandbox.
It appears a forward declaration is causing an issue when specializing some template functions within a template class. I am specializing the class also as it's necessary in order to specialize the function, and this seems to be causing the issue.
Edit: Second question about pre-creating functions for process function:
processor.H
namespace OM{
template<typename MatchT> //fwd decl. ERROR 2. see below.
class Manager;
template<typename MatchT>
class Processor
{
public:
Processor(Manager<MatchT>& mgr_):_manager(mgr_) {}
template<int P>
void process();
void doProcess();
private:
Manager<MatchT>& _manager;
template<int P, int... Ps>
struct table : table<P-1,P-1, Ps... > {};
template<int... Ps>
struct table<0, Ps...>
{
static constexpr void(*tns[])() = {process<Ps>...};
};
static table<5> _table;
};
}
#include "processor.C"
processor.C
namespace OM{
#include "MyManager.H" (includes MyManager/MyConfig)
template<typename MatchT>
template<int P>
inline void Processor<MatchT>::process()
{
...
_manager.send(); //this works..
}
template <> template <>
inline void Processor<MyManager<MyConfig> >::process<1>()
{
_manager.send(); //ERROR 1 - see below.
}
//ERROR here:
template<typename MatchT>
void doProcess()
{
Processor<MatchT>::_table::tns[2](); ERROR 3 below.
}
}
compile errors:
1. error: invalid use of incomplete type 'class Manager <MyManager<MyConfig> >'
2. error: declaration of 'class Manager<MyManager<MyConfig> >'
class Manager;
3. error: no type name '_table' in "class Processor<MyManager<MyConfig> >'
I'm not calling this from a specialized function, so I'm not sure
why I'm getting this.
I can move things around a bit to ensure the _manager calls are not within the specialized functions, but I'd rather not if I don't have to.
I played around with this, I think now I get a similar result.
The problem is the template specialisation and forward declaration together. This should be eqvivalent:
template<typename T> struct A;
template<typename T> class B
{
template<int N>
T f();
};
template<typename T> class B<A<T>>
{
A<T> *a;
template<int N>
T f();
};
template<typename T> struct A{ T i=1; };//works
template<>
template<>
int B<A<int>>::f<1>()
{
return a->i + 1;
}
//template<typename T> struct A { T i = 1; };//error
int main()
{
B<A<int>> b;
}
The compilation for templates comes in two stages:
First, it checks syntax and (some) dependence. So, for example if a in B<A<T>> was not a pointer/reference, but the object itself, it could compile, if that B<A<T>> is constructed after A is defined. (worked for me)
So the second is when the compiler inserts the arguments, here, the compiler must know all objects to generate code.
When fully specialising, as above, the compiler is forced to know all types. It already knows, that f function depends on the implementation of A, so it cannot generate the code.
Therefore you have to define A or Manager before the function specialisation.
Why are we suppose to use template parameters at front of every function even if we are not using deduced template parameters in the function. As we can see that i am not using template parameter _T in printP() function (around 30) then why it is required to include template syntax at front of this function.
NOTE: This is very simplified version of my big class, and it might look silly because it is very small but, consider a situation where you are using template for only few [2-3] function of your class but you are bound to type (even copy past) this lengthy template syntax at front of every function but i am asking why??.
Is there any way to get of this
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
template<typename _T>
class Thing{
int _p;
_T _k;
public:
Thing(int p, _T k):_p(p),_k(k){}
void printK();
void printP();
};
template<typename _T>
void Thing<_T>::printK(){
cout << _k << endl;
}
template<typename _T>
void Thing<_T>::printP(){
cout << _p << endl; // as we can see that i am not using template paramerter "_T"
} // here in this function then why it is required to include template syntax
int main()
{
Thing<int> a(1,2);
a.printK();
a.printP();
}
Because the function PrintK is member of template class Thing<_T>. For a member function definition outside the class, the function name also includes class name(to which it belongs, here it belongs to Thing), since Thing is template, so function name requires you to provide template parameter (T here).
e.g.
Function definition outside class requires the following syntax
**
return type class name:: function name (argument list)
*
Here class (Thing) is template class, so its name will also require type (like Thing<_T>).
I hope you got my point.
Its usually a good idea to restrict the members and functions of a template class to those that are dependent on the template parameters. Non-dependent members and functions can be put in a separate non=template class (is there a better name?). For example:
#include <iostream>
using namespace std;
class ThingBase
{
public:
ThingBase(int p)
: _p(p)
{
}
void printP();
protected:
int _p;
};
void ThingBase::printP(){
cout << _p << endl;
}
template<typename _T>
class Thing : public ThingBase {
_T _k;
public:
Thing(int p, _T k)
: ThingBase(p),
_k(k){}
void printK();
};
template<typename _T>
void Thing<_T>::printK(){
cout << _k << endl;
}
int main()
{
Thing<int> a(1,2);
a.printK();
a.printP();
}
There are 2 different specialization template forms in c++
One is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
template<>
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
The other is:
#include <iostream>
using namespace std;
template<class T>
class mytest
{
public:
void method(T input){}
};
void mytest<int>::method(int input)
{
cout << "ok" << endl;
}
int main()
{
mytest<bool> mt;
mt.method(1);
system("pause");
return 0;
}
They can also be compiled in VS2013. I notice that the second implementation of specialization template situation is just lack of template<>
I want to know what the difference is between the 2 forms above.
Visual C++ is wrong.
The standard is very clear about this.
First,
Members of an explicitly specialized class template are defined in the
same manner as members of normal classes, and not using the template<>
syntax.
Meaning that, for explicit specialization of a class template, the member definition strictly do not require template<>.
Example:
template<class T>
struct A {
};
template<>
struct A<int> {
void f(int);
};
// template<> not used for a member of an
// explicitly specialized class template
void A<int>::f(int) { / ... / }
And,
A member or a member template of a class template may be explicitly
specialized for a given implicit instantiation of the class template,
even if the member or member template is defined in the class template
definition. An explicit specialization of a member or member template
is specified using the syntax for explicit specialization.
Meaning that, for a template that is not "explicit specialized", you can specialize its member, with the template<> (syntax for explicit specialization)
Example,
template<class T>
struct A {
void f(T);
};
// specialization
template<>
void A<int>::f(int);
The above examples are directly copied out from standard. To summarize, if the class is already explicitly specialized, do not use template<>, else if the class relies on implicit instantiation, use template<>.
Your first example compiles fine in Clang, and your second example fails to compile in Clang, you will get an error:
error: template specialization requires 'template<>'
template <class T> class mycontainer { ... };
template <> class mycontainer <char> { ... };
The first line is the generic template, and the second one is the specialization.
When we declare specializations for a template class, we must also define all its members, even those identical to the generic template class, because there is no "inheritance" of members from the generic template to the specialization.
http://www.cplusplus.com/doc/tutorial/templates/
The following code doesn't compile with gcc, but does with Visual Studio:
template <typename T> class A {
public:
T foo;
};
template <typename T> class B: public A <T> {
public:
void bar() { cout << foo << endl; }
};
I get the error:
test.cpp: In member function ‘void B::bar()’:
test.cpp:11: error: ‘foo’ was not declared in this scope
But it should be! If I change bar to
void bar() { cout << this->foo << endl; }
then it does compile, but I don't think I have to do this. Is there something in the official specs of C++ that GCC is following here, or is it just a quirk?
David Joyner had the history, here is the reason.
The problem when compiling B<T> is that its base class A<T> is unknown from the compiler, being a template class, so no way for the compiler to know any members from the base class.
Earlier versions did some inference by actually parsing the base template class, but ISO C++ stated that this inference can lead to conflicts where there should not be.
The solution to reference a base class member in a template is to use this (like you did) or specifically name the base class:
template <typename T> class A {
public:
T foo;
};
template <typename T> class B: public A <T> {
public:
void bar() { cout << A<T>::foo << endl; }
};
More information in gcc manual.
Wow. C++ never ceases to surprise me with its weirdness.
In a template definition, unqualified names will no longer find members of a dependent base (as specified by [temp.dep]/3 in the C++ standard). For example,
template <typename T> struct B {
int m;
int n;
int f ();
int g ();
};
int n;
int g ();
template <typename T> struct C : B<T> {
void h ()
{
m = 0; // error
f (); // error
n = 0; // ::n is modified
g (); // ::g is called
}
};
You must make the names dependent, e.g. by prefixing them with this->. Here is the corrected definition of C::h,
template <typename T> void C<T>::h ()
{
this->m = 0;
this->f ();
this->n = 0
this->g ();
}
As an alternative solution (unfortunately not backwards compatible with GCC 3.3), you may use using declarations instead of this->:
template <typename T> struct C : B<T> {
using B<T>::m;
using B<T>::f;
using B<T>::n;
using B<T>::g;
void h ()
{
m = 0;
f ();
n = 0;
g ();
}
};
That's just all kinds of crazy. Thanks, David.
Here's the "temp.dep/3" section of the standard [ISO/IEC 14882:2003] that they are referring to:
In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [Example:
typedef double A;
template<class T> class B {
typedef int A;
};
template<class T> struct X : B<T> {
A a; // a has typedouble
};
The type name A in the definition of X<T> binds to the typedef name defined in the global namespace scope, not to the typedef name defined in the base class B<T>. ] [Example:
struct A {
struct B { /* ... */ };
int a;
int Y;
};
int a;
template<class T> struct Y : T {
struct B { /* ... */ };
B b; //The B defined in Y
void f(int i) { a = i; } // ::a
Y* p; // Y<T>
};
Y<A> ya;
The members A::B, A::a, and A::Y of the template argument A do not affect the binding of names in Y<A>. ]
This changed in gcc-3.4. The C++ parser got much more strict in that release -- per the spec but still kinda annoying for people with legacy or multi-platform code bases.
The main reason C++ cannot assume anything here is that the base template can be specialized for a type later. Continuing the original example:
template<>
class A<int> {};
B<int> x;
x.bar();//this will fail because there is no member foo in A<int>
VC doesn't implemented two-phase lookup, while GCC does. So GCC parses templates before they are instantiated and thus finds more errors than VC.
In your example, foo is a dependent name, since it depends on 'T'. Unless you tell the compiler where it comes from, it cannot check the validity of the template at all, before you instantiate it.
That's why you have to tell the compiler where it comes from.