I have created an ordinary class with a templated method, and all the method instances are explicit and inlined.
Like
class MyClass
{
template<int N> inline void MyMethod();
template<> inline void MyMethod<1>() { cout << 1; }
template<> inline void MyMethod<2>() { cout << 2; }
};
I needed to use the template<> syntax to have it compile. I tried other solutions, such as the explicit definition of the method outside the class declaration, with syntax variants, to no avail. (This was made under VS2008, not tried on later versions.)
I have two questions:
is this portable ?
does it make sense ?
The way you wrote it is wrong and it won't work.
Member method specializations must be put out of your class:
class MyClass
{
template<int N> void MyMethod();
};
template<> void MyClass::MyMethod<1>() { }
template<> void MyClass::MyMethod<2>() { }
It's portable and if it makes sense mostly depends on your actual problem, it's hard to say from your example.
You can't fully specialize member template in class body. Partial specialization are allowed though. Full specializations must be declared/defined outside class body (and definitions should be placed in cpp file if not declared inline).
For reference, this question.
Related
class TestClass
{
public:
static int testMember;
template<class T> static T* Foo()
{
//Defination....
}
}
//int TestClass::testMember; //Duplicate definition
Why can't I define a member field in .hpp while I can define member functions in .hpp?
Does it must be defined in a .cpp file?
Why can't I define a member field in .hpp
You can.
C++ doesn't care what you name your files, and doesn't care what extension the files have.
What you can't do is define the variable more than once. That would obviously violate the one definition rule.
In order to satisfy the one definition rule, you have two options:
In C++17 or later, make the variable inline.
class TestClass
{
public:
static inline int testMember;
template<class T> static T* Foo()
{
//Defination....
}
}
In any version of C++, place the definition in your code where it will be compiled exactly once.
Why ... [can I] define member functions in .hpp?
Because member functions, defined in the class, are implicitly inline. Just like your variable could be.
As Drew Dormann has mentioned, template member functions (static or not) are implicitly inline.
The same goes for class templates:
template <typename>
class TestClass
{
public:
static int testMember;
template<class T> static T* Foo()
{
//Definition....
}
};
// prior to C++17 you definition MUST be outside the class in the header
template <typename T>
int TestClass<T>::testMember{};
If only define this method it will have a compiler error.
void classA::testMethod() {
}
And so it must be declared first:
class classA {
void testMethod();
};
Why should these be declared?
I know for common C method methods it is not needed declare, but they can just be defined:
void test() {
}
There are several secondary reasons both objective and subjective (i.e. allows to specify visibility, serves as an interface for the class and probably several others related to compiling and linking phases and TU symbols visibility, not to mention a class is the basic encapsulation unit, with all that implies) but an unquestionable one is that the standard dictates it:
N3797 - class.mfct/p2
A member function may be defined (8.4) in its class definition, in
which case it is an inline member function (7.1.2), or it may be
defined outside of its class definition if it has already been
declared but not defined in its class definition. A member function
definition that appears outside of the class definition shall appear
in a namespace scope enclosing the class definition. Except for member
function definitions that appear outside of a class definition, and
except for explicit specializations of member functions of class
templates and member function templates (14.7) appearing outside of
the class definition, a member function shall not be redeclared.
emphasis mine.
You don't need to declare the method before you define it, but you need to declare class methods in the class. Else it wouldn't be a class method.
That may seem like a contradiction, but a definition is also a declaration. So what this means is that the definition may appear in the class itself:
class A {
void testMethod() { /*...*/ }
};
[edit]
Also, practically speaking, inside the class declaration there are private, protected and public parts. This is needed to for encapsulation. If you could declare methods outside the class, you would lose encapsulation. Anybody could access private members merely by defining extra getters and setters, even when those would not make sense. Class invariants would become meaningless.
It helps encapsulation. If you have a class A
class A {
public:
foo();
bar();
}
You can be sure that only methods foo and bar mess with the private data members of the class. (Or pointer magic or undefined behavior of course)
All of the previous answers are correct as far as they go, but
they fail to point out the reason behind the rule. In C++,
a class definition is closed; you cannot add to it later. This
is necessary for non-static data members, since they determine
the size (and the implicitly generated special functions), but
it is a basic principle in C++ for all class members: not just
data, but functions, types, etc. It is considered essential for
good encapsulation.
This is true for most (but not all) languages which support the
concept of class.
This also explains why it the situation is different for
namespaces (which aren't closed).
Note the use of the qualifier ::. It means
on the left you have a namespace or class identifier
on the right you have a namespace, class, or method / function identifier
So writing void A::testMethod() assumes that there is a class or namespace A defined - this is how C++ is defined. And this applies to
void A::testMethod();
as well as to
void A::testMethod()
{
}
Also note the global namespace where you have indeed nothing at the left of :: as in
void ::testMethod()
{
}
And by definition the global namespace is always defined so the above code defines a function similar to C-style without the qualifier.
Even if it were not mandated by the standard, there are the following two reasons why you need to declare all class methods in the class definition.
You can only declare something as public, private or protected in the class declaration, you can't do so at the method definition in the .cpp file. So what visibility would your free-standing class method have?
If the standard decided to select one of the three as the default (C++ defaults to private), and place that visibility on your method, you now have a scoping problem. Even the most restrictive visibility (private) means that you can use the method in any other member method, including those defined before it in the source file. Without the declaration in the class definition, those earlier functions would not be aware of your free standing method, thus you violate the scoping rules.
In your foo.h header:
class foo
{
public:
foo() {}
virtual ~foo() {}
declaredMethod();
};
In your foo.cpp
foo::declaredMethod()
{
...
freeStandingMethod(); // This should be legal, but it can't work since we
// haven't seen foo::freeStandingMethod() yet
...
}
foo::freeStandingMethod()
{
...
}
Even if you could make this work in the same .cpp file, it's legal to place foo::freeStandingMethod() in a different .cpp file from foo::declaredMethod() at which point this becomes impossible.
This is not an answer, but you might find it informative and fun.
Adding 2 template functions to your class will effectively allow you to call any free function that takes an object of that class as the first parameter:
#include <string>
#include <iostream>
struct puppy {
puppy(std::string name)
: _name(std::move(name))
{}
const std::string& name() const noexcept {
return _name;
}
void set_name(std::string name) {
_name = std::move(name);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args) const
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
template<class F, class ...Args>
auto perform(F&& f, Args&&...args)
-> decltype(f(*this, std::forward<Args>(args)...))
{
return f(*this, std::forward<Args>(args)...);
}
private:
std::string _name;
};
void woof(const puppy& p) {
std::cout << "puppy " << p.name() << " woofs!" << std::endl;
}
void indented_woof(const puppy&p, size_t indent) {
std::cout << std::string(indent, ' ');
woof(p);
}
void complex_woof(const puppy& p, int woofs)
{
std::cout << "attention!" << std::endl;
for (int i = 0 ; i < woofs ; ++i) {
p.perform(indented_woof, 4);
}
}
std::string name_change(puppy& p, std::string(new_name))
{
auto old_name = p.name();
p.set_name(std::move(new_name));
return old_name;
}
int main()
{
puppy fido { "fido" };
fido.perform(woof);
fido.perform(complex_woof, 10);
auto old_name = fido.perform(name_change, "bonzo");
fido.perform(woof);
std::cout << "changed name from " << old_name << std::endl;
return 0;
}
"Methods" or "member functions" (as is the more common terminology in C++) are part of the class declaration. Since you must declare a C++ class in one single place, you must make sure that all "member functions" (or "methods") are already present in that declaration.
I know for common C method methods it is not needed declare, but they
can just be defined
When you refer a "common C method" in C++, you actually mean a "common function". Note that you can declare classes anywhere you can declare such functions.
Also, note that you can declare a member function with a body. You do not have to separate declaration and definition. I.e. this is perfectly valid:
class A{
void privateMethod() {
// do something here...
}
public:
void publicMethod() {
// do something here...
}
};
why should declare these? I know for common c method, there is no need to declare, instead of it just define it:
There is no method in C, just attribute of an struct, wich can be function Pointeur, then associated to a function addresse.
Furthermore you have to declare it in the class definition for the same reason you do it in C:
The compilateur will transform this pre-declaration into a function pointeur then associate to the said methode int the construction of your object.
If a definition of a C++ class should be transformed to a C struct the code would be like this:
struct Aclass {
void (*Amethode))(int);
}
void Amethode(int) { return (0); }
Aclass primaryObject = {&Amethode};
Aclass* AclassConstructor() {
Aclass* object;
object = malloc(sizeof(Aclass));
memcpy(object, primaryObject, sizeof(Aclass));
return (object);
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What’s the scope of inline friend functions?
Consider simple program :
template<typename T> struct foo{
friend void bar(){}
};
int main(){
foo<int>(); foo<float>();
}
Above code breaks the ODR rule, I wonder why? , also where is the scope of function bar ?
friend functions are not member functions; you just declare friendship inside a class, but the function is always a free function. If you define it inside a class template class, you will end up defining it as many times as template instances you have.
I will try to explain that with code. For our purposes, your code is equivalent to this:
template<typename T> struct foo{
};
template<> struct foo<int>{
friend void bar();
};
void bar() {};
template<> struct foo<double>{
friend void bar();
};
void bar() {};
int main(){
foo<int>(); foo<float>();
}
Because your code defines the free function void bar() twice, or lets rather say, your templates produces for each instantiation a new function named void bar(), which happens to have the exact same signature each time, therefore you have multiple functions with the same signature, which is a breach of ODR.
The technique at hand is called "Friend Name Injection", because you inject a name into the surrounding namespace.
You have defined the bar inside your struct. This leads to double definition of bar func, once per template instantiation. Friend should be only a declaration of some entity. The entity itself (func in your case) should be defined elsewhere. Replace your bar definition with friend void bar(); declaration and define your bar in another place.
In the sample:
#include <iostream>
using namespace std;
class B
{
public:
virtual void pvf() = 0;
};
template <class T>
class D : public B
{
public:
D(){}
virtual void pvf() {}
private:
string data;
};
template <>
class D<bool> : public B
{
public:
D();
virtual void pvf(){ cout << "bool type" << endl; }
};
int main()
{
D<int> d1;
D<bool> d2;
}
I get the following error:
test.cpp:(.text+0x1c): undefined reference to `D<bool>::D()'
Note that the reason I don't just specialize the D() by itself is I want to eliminate the need for string D<T>::data in the D<bool> case.
Why do I need to re-implement D() in D<bool>? Seems like there should be a way for me to tell the compiler to use the version from D<T>.
Is there any way to do a simple specialization like this without having to re-implement methods?
Each specialisation of a class template gives a different class - they do not share any members with each other. Since you've explicitly specialised the entire class, you don't get any of the members from the template, and must implement them all.
You can explicitly specialise individual members, rather than the entire class:
template <> void D<bool>::pvf(){ cout << "bool type" << endl; }
Then D<bool> will still contain all the members of the class template that you haven't explicitly specialised, including the default constructor.
No, there is not.
Specialization is behaving very differently than inheritence. It has no connection to the generic template version.
When you use/instantiate a template, the compiler will create a new type name, and then look for how this type is defined. When it finds a specialization, then it takes that as the definition for the new type. When it does not, it takes the generic template and instantiates it.
Therefore they have no connection, and you are just writing an entirely new class, just with a special name for the compiler to find in case of someone using/instantiating the template to find it under that name.
The problem is your erroneous assumption that there is anything common between D<A> and D<B>. Template instances are types, and two different instances are two different types, end of story. It only so happens that instances of the same template have formally similar code, but with specialization you can define any type you like. In short, every type that you define explicitly is entirely independent, and there is no commonality across specialized template instances, even if they happen to have the same name.
For example:
template <typename T> struct Foo
{
T & r;
const T t;
void gobble(const T &);
Foo(T *);
};
template <> struct Foo<int>
{
std::vector<char> data;
int gobble() const;
Foo(bool, int, Foo<char> &);
};
The types Foo<char> and Foo<int> have nothing to do with one another, and there is no reason why any part of one should have any use inside the other.
If you want to factor out common features, use private inheritance:
template <typename> struct D : private DImpl { /* ... */ }
You need to reimplement it because D<T> and D<bool> are totally unrelated classes (they just happen to "share the name"). That's just how templates work.
If you want the classes to share construction code, just put that code inside B::B (i.e. the same thing you do every time you want to reuse code in different branches of the same hierarchy: move the code up and let inheritance handle the rest).
Consider that D<T>::D() will be responsible for default-constructing string data, and that D<bool> doesn't have any such member. Clearly there is no way to use the same emitted code in each case.
However, if your default constructor doesn't do anything (in either version here), just omit it and allow the compiler to do the work.
I can't get this to compile at all. I may not be possible but I don't know why it should not be.
class A {
template <typename T>
class B {
int test() { return 0; }
};
//template <> class B<int>; <-with this, namepace error
B<int> myB_;
};
template <> class A::B<int> {
int test() {
return 1;
}
};
As it appears the compiler complains "The explicit specialization "class A::B" must be declared before it is used."
If I try to provide the froward declaration in the commented line, the compiler complains
"The explicit specialization "B" must be declared in the namespace containing the template."
We use 2 different compilers here. This error is from IBM's "xl" compiler on AIX but I get similar errors with different verbage when compiling on our Sun systems.
It seems like a catch-22.
Obviously, this is a highly contrived, simplistic example but, it represents the problem.
I want to define a template class within a class because the template class is only relevent to the containing class. There should be no access to the template from outside the class.
Am I missing something?
You are correct. This is not possible to do (as far as I know). Your member declaration causes an implicit instantiation before the explicit specialization was declared. But how would you want to declare it? You cannot do that in class scope. Others have felt that this is an ugly restriction.
You could work around this by making the class member a pointer. This would not need to implicitly instantiate the class at that point, but rather at the point where you create the object in the end. I realize that this is an ugly work around. So better find other ways to do this.
For instance partial specializations are allowed in class scope. So you could add a dummy template parameter, then you can specialize this in the class before the member declaration. Likewise, i find this ugly, but it would not disturb things that much, I feel.
You could work around the issue by using an unnamed namespace for privacy:
namespace {
template <typename T>
class B {
int test() { return 0; }
};
template <> class B<int> {
int test() {
return 1;
}
};
}
class A {
B<int> myB_;
};
This will compile, but if A needs to be visible outside this compilation unit, you'll need more elaborate machinery (e.g., interface and factory or Pimpl).
B is not a template class and you are trying to specialize it. That is the cause for the error. You can check these two errors C2913 and C3413.
Is this what you are looking for?
class A
{
template<class T>
class B
{
inline int test()
{
return 0;
}
};
A::B<int> myB_;
};