explicit instantiation after specialization - c++

#include <iostream>
using namespace std;
template <typename>
class Test
{
void fun() { cout << "test" << endl; }
void bar() { cout << "bar"; }
};
template<>
class Test<int>
{
void fun(){}
};
template void Test<int>::fun();
I got an error:
error: template-id 'fun<>' for 'void Test::fun()' does not match any template declaration
But why?
I know it work if add template for fun in Test e.g.
template<>
class Test<int>
{
template <typename>
void fun(){}
};
template void Test<int>::fun<bool>();
For function template
template<class T> void sort(Array<T>& v) { /*...*/ } // primary template
template<> //explicit specialization of sort(Array<String>)
void sort<String>(Array<String>& v); // after implicit instantiation
template
void sort(Array<String>& v);// no matter before/after void f(Array<String>& v) , it both works
void f(Array<String>& v) {
sort(v); // implicitly instantiates sort(Array<String>&),
} // using the primary template for sort()

An explicit specialisation (that is, not a partial specialisation) is no longer a template. That means all of its members really exist (as if they were instantiated), so you cannot (and need not) instantiate them.

Related

Constraints on explicit specialization of a member of a class template

According to [temp.expl.spec]/16:
A member or a member template of a class template may be explicitly specialized for a given implicit instantiation of the class template ...
After some tests, I found that the specialization should match the member in the implicit instantiation of the class template, meaning they should be the same type. For example,
template<class T> struct A {
void f(T);
static T i;
};
template<> void A<int>::f(int); // ok
// template<> void A<int>::f(char); // error
template<> int A<int>::i; // ok
// template<> char A<int>::i; // error
Where does the standard specify such constraints?
As pointed out in the comment of Evgeny:
Instancing struct A for type int, you get a method void f(int); defined.
If you want to implement template<> void A<int>::f(char) { } ā€“ there is no such method defined in struct A<int>.
To achieve this, you could specialize the whole struct A for int.
The alternative is (as already shown in answer of user846834) to make the method in quest a template itself.
Sample code:
#include <iostream>
template <class T>
struct A {
void f(T);
};
template <>
void A<int>::f(int) { std::cout << "void A<int>::f(int) called.\n"; }
#if 0 // ERROR
void A<int>::f(char) { std::cout << "void A<int>::f(char) called.\n"; }
#endif // 0
template <class T>
struct B {
void f(T);
};
template <>
struct B<int> {
void f(char);
};
void B<int>::f(char) { std::cout << "void B<int>::f(char) called.\n"; }
template <class T>
struct C {
template <class U = T>
void f(U) { std::cout << "void C<T>::f(U) called.\n"; }
};
template <> template <>
void C<int>::f(char) { std::cout << "void C<int>::f(char) called.\n"; }
int main()
{
A<int> a; a.f(0);
B<int> b; b.f(0);
C<int> c; c.f('0');
// done
return 0;
}
Output:
void A<int>::f(int) called.
void B<int>::f(char) called.
void C<int>::f(char) called.
Live Demo on coliru
In the examples of the link you have given, it is only the non-type template parameters (X1, X2) that were specified to be of different type than T.
And only they can be specified as different. The type template parameters need to be the same as the specialization.
template<class T> struct A {
void f(T);
template<class X1> void g1(T, X1);
template<class X2> void g2(T, X2);
void h(T) { }
};
// member template specialization
template<> template<>
void A<int>::g1(int, char); // X1 deduced as char
template<> template<>
void A<int>::g2<char>(int, char); // X2 specified as char

Friend explicit specialization of function template and ADL

Why in the following the partial specialization is not selected by ADL?
template<class T>
void func1(T&){ // selected
...
}
namespace first{
template<class R>
struct foo{
friend void func1<>(foo<R>&){ // expected
cout << "foo.func1" <<endl;
}
};
}
foo<int> f;
func1(f);
Template parameters are unrelated with friend declarations. You'll need to carry them disambiguated in thefriend declaration:
template<class R>
struct foo{
template<typename U>
friend void func1<U>(foo<U>&){
cout << "foo.func1" <<endl; // cat();
}
};
Also for your case you should decide, if you want to put the friend definition inlined as above, or just provide a declaration:
template<class R>
struct foo{
template<typename U>
friend void ::func1<U>(foo<U>&);
};
The latter should match the friend template function in the global namespace explicitly, and specialization can be made as necessary:
template<>
void func1(int&){
// ...
}
template<>
void func1(std::string&){
// ...
}
// a.s.o.
You don't need to provide an specialization of func1. Just provide an overload:
namespace first {
template <class R>
struct foo {
friend void func1(foo& ){
std::cout << "foo.func1" << std::endl;
}
};
}
int i;
first::foo<int> f;
func(i); // calls ::func<int>
func1(f); // calls first::func1(first::foo<int>& );
Otherwise, you can friend a specizliation, but you can't define a specialization in the class body:
template <class R>
struct foo {
friend void func1<>(foo& ); // friends ::func1<foo<R> >
};

C++ template, static function specialization

I have a syntax error with my template
I would like to partial specialize a static function of my template class
class.hpp
template <typename Foo, size_t bar = 26>
class MyClass
{
MyClass();
static void function();
};
#include "class.tpp"
class.tpp
template <typename Foo, bar>
MyClass<Foo, bar>::MyClass()
{ }
template <typename Foo>
inline
void
MyClass<Foo, 6>::function()
{
// ...
}
template <typename Foo>
inline
void
MyClass<Foo, 26>::function()
{
// ...
}
error: template definition of non-template
I just want to implement MyClass<Foo, bar>::function for bar == 26 and bar == 6
How to do that properly ?
Thanks
The function is not a template itself, it is only inside a class template. You can specialize the class for those cases, but not the function itself.
template <class Foo>
class MyClass<Foo, 26>
{
static void function() { ... }
};
Provided you have specialized the class like so, you can only declare the function inside the class, and define it outside like so:
template <class Foo>
void MyClass<Foo, 26>::function() { ... }
If you don't specialize it beforehand, you'll get a compilation error for using an incomplete type.
You might also find this question and answer on specializing a single function inside a class template relevant.
You cannot partial specialize method like that.
You may partial specialize the whole class.
or as alternative, you may forward the implementation to some helper:
struct that you may specialize as you want.
overload (using some dispatching):
namespace detail
{
template <typename Foo, std::size_t bar>
void function_impl(MyClass<Foo, bar>& that)
{
// Generic case.
}
template <typename Foo>
void function_impl(MyClass<Foo, 6>& that)
{
// special case <Foo, 6>.
}
template <typename Foo>
void function_impl(MyClass<Foo, 26>& that)
{
// special case <Foo, 26>.
}
}
template <typename Foo, std::size_t bar>
inline
void
MyClass<Foo, bar>::function()
{
detail::function_impl(*this);
}
After doing some research; Partial Specialization for member functions of a class template are not allowed, so one would have to specialize the whole class which can be a problem if the actual class is quite large. If you are trying to separate the implementation from the declaration having a wrapper or helper will work, but you must defined that and the partial specialization first. Check out this code here for it compiles, builds and outputs the appropriate values using MSVC 2015 CE.
MyClass.h
#ifndef MY_CLASS_H
#define MY_CLASS_H
#include <iostream>
// Helper - Wrapper Class
template<typename Foo, size_t Bar>
class specialized {
public:
inline static void function();
};
// Partial Specialization
template<typename Foo>
class specialization<Foo, 6> {
public:
inline static void function();
};
// Actual Class
template<typename Foo, size_t Bar = 26>
class MyClass {
private:
specialized<Foo, Bar> func;
public:
MyClass();
inline void function(); // Works
// inline static void function(); // Compiler Error
}; // MyClass
#include "MyClass.inl"
#endif // MY_CLASS_H
MyClass.inl
// Helper - Wrapper
template<typename Foo, size_t Bar>
inline void specialized<Foo, Bar>::function() {
std::cout << "26" << std::endl;
} // function
// Specialized
template<typename Foo>
inline void specialized<Foo, 6>::function() {
std::cout << "6" << std::endl;
} // function
// Constructor
template<typename Foo, size_t Bar>
MyClass<Foo, Bar>::MyClass() {
} // MyClass
// Class Member Function
template<typename Foo, size_t Bar>
inline void MyClass<Foo, Bar>::function() {
func.function();
} // function
MyClass.cpp
#include "MyClass.h"
Main.cpp
#include "MyClass.h"
int main() {
MyClass<float, 6> a;
a.function(); // Prints Out 6
MyClass<float, 26> b;
b.function(); // Prints Out 26
MyClass<float> c;
c.function(); // Prints Out 26
MyClass<float, x != 6> d;
d.function(); // Prints Out 26
return 0;
} // Main

Template specific methods

If I have a class A
template <typename T>
class A { public: void print() const; };
I can write specific version of my methode print for specific template values my doing
template<> void A<bool>::print() const { printf("A w/ type bool\n"); }
template<> void A<int>::print() const { printf("A w/ type int\n"); }
and the calling the method print will just call the code of the good implementation (of the compiler tell me if I don't have an implementation for a specific template.
Now, if I have multiples types in my class B's template
template <typename T1, typename T2>
class B { public: void print() const; };
and if I try to do the same as before, let's say for T2
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
I get an compiler error :
error: invalid use of incomplete type 'class B<T1,bool>'
error: declaration of 'class B<T1, bool>'
What am I doing wrong ?
EDIT
My real life B class contains other methods with I do not want to specify (they work in the general case)
Having a partially specified class decalred makes that those generic methods aren't natively availlable
You can't partial specialize a function/method.
But you can partial specialize the whole class:
template <typename T1, typename T2> class B;
template<typename T1> class B<T1, bool>
{
public:
void print() const { printf("B w/ type bool\n"); }
};
What am I doing wrong?
template<> void A<bool>::print() const { printf("A w/ type bool\n"); }
template<> void A<int>::print() const { printf("A w/ type int\n"); }
These member functions are like normal functions, they are not templates with un-substituted parameters, so you are just providing definitions for the symbols, which will be used when those functions get called. (And like normal functions, if those definitions are in a header and you don't declare them inline you will get multiple definitions errors for them.)
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
This is not the same, this is providing a definition for a member function of a class template partial specialization. i.e. it's a template that will be used to generate code for the member of that partial specialization, but you haven't declared any such partial specialization, so you can't define its members.
You can make it compile by defining the partial specialization first:
// primary template
template <typename T1, typename T2>
class B { public: void print() const; };
// partial specialization
template<typename T1>
class B<T1,bool> { public: void print() const; };
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
However it is often inconvenient to have to repeat the entire class template definition just to define a partial specialization for one or two members, so it might be worth taking one of the alternative designs shown in other answers.
With templates it's best to decompose each part of the specialisation into its own template function or traits class.
Here's a clean way to do what you want:
template<typename T>
const char* type_name()
{
return "unknown";
};
template<>
const char* type_name<int>()
{
return "int";
}
template<>
const char* type_name<bool>()
{
return "bool";
}
struct foo {};
template<>
const char* type_name<foo>()
{
return "my custom foo";
}
struct bar {};
template <typename T>
class A {
public:
void print() const {
cout << "A w/ type " << type_name<T>() << '\n';
}
};
int main() {
A<bool> ab;
A<int> ai;
A<foo> af;
A<bar> abar;
ab.print();
ai.print();
af.print();
abar.print();
return 0;
}
output:
A w/ type bool
A w/ type int
A w/ type my custom foo
A w/ type unknown
Program ended with exit code: 0
With tag dispatching, you might do:
#include <iostream>
template<typename A, typename B>
class X
{
private:
template <typename U> struct Tag {};
template <typename U>
void print(Tag<U>) const;
void print(Tag<bool>) const { std::cout << "bool\n"; }
void print(Tag<int>) const{ std::cout << "int\n"; }
public:
void print() const { print(Tag<B>()); }
};
int main()
{
X<void, bool>().print();
X<void, int>().print();
}

Function template specialization format

What is the reason for the second brackets <> in the following function template:
template<> void doh::operator()<>(int i)
This came up in SO question where it was suggested that there are brackets missing after operator(), however I could not find the explanation.
I understand the meaning if it was a type specialization (full specialization) of the form:
template< typename A > struct AA {};
template<> struct AA<int> {}; // hope this is correct, specialize for int
However for function templates:
template< typename A > void f( A );
template< typename A > void f( A* ); // overload of the above for pointers
template<> void f<int>(int); // full specialization for int
Where does this fit into this scenarion?:
template<> void doh::operator()<>(bool b) {}
Example code that seems to work and does not give any warnings/error (gcc 3.3.3 used):
#include <iostream>
using namespace std;
struct doh
{
void operator()(bool b)
{
cout << "operator()(bool b)" << endl;
}
template< typename T > void operator()(T t)
{
cout << "template <typename T> void operator()(T t)" << endl;
}
};
// note can't specialize inline, have to declare outside of the class body
template<> void doh::operator()(int i)
{
cout << "template <> void operator()(int i)" << endl;
}
template<> void doh::operator()(bool b)
{
cout << "template <> void operator()(bool b)" << endl;
}
int main()
{
doh d;
int i;
bool b;
d(b);
d(i);
}
Output:
operator()(bool b)
template <> void operator()(int i)
I've looked it up, and found that it is specified by 14.5.2/2:
A local class shall not have member templates. Access control rules (clause 11) apply to member template names. A destructor shall not be a member template. A normal (non-template) member function with a given name and type and a member function template of the same name, which could be used to generate a specialization of the same type, can both be declared in a class. When both exist, a use of that name and type refers to the non-template member unless an explicit template argument list is supplied.
And it provides an example:
template <class T> struct A {
void f(int);
template <class T2> void f(T2);
};
template <> void A<int>::f(int) { } // non-template member
template <> template <> void A<int>::f<>(int) { } // template member
int main()
{
A<char> ac;
ac.f(1); //non-template
ac.f(ā€™cā€™); //template
ac.f<>(1); //template
}
Note that in Standard terms, specialization refers to the function you write using an explicit specialization and to the function generated using instantiation, in which case we have to do with a generated specialization. specialization does not only refer to functions you create using explicitly specializing a template, for which it is often only used.
Conclusion: GCC gets it wrong. Comeau, with which i also tested the code, gets it right and issues a diagnostic:
"ComeauTest.c", line 16: error: "void doh::operator()(bool)" is not an entity that
can be explicitly specialized
template<> void doh::operator()(bool i)
Note that it isn't complaining about the specialization of the template for int (only for bool), since it doesn't refer to the same name and type: The function type that specialization would have is void(int), which is distinct from the function type of the non-template member function, which is void(bool).