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).
Related
I have a templated class, for which I want to specialize one of the methods for integral types. I see a lot of examples to do this for templated functions using enable_if trait, but I just can't seem to get the right syntax for doing this on a class method.
What am I doing wrong?
#include <iostream>
using namespace std;
template<typename T>
class Base {
public:
virtual ~Base() {};
void f() {
cout << "base\n";
};
};
template<typename Q>
void Base<std::enable_if<std::is_integral<Q>::value>::type>::f() {
cout << "integral\n";
}
template<typename Q>
void Base<!std::enable_if<!std::is_integral<Q>::value>::type>::f() {
cout << "non-integral\n";
}
int main()
{
Base<int> i;
i.f();
Base<std::string> s;
s.f();
return 0;
}
the above code does not compile:
main.cpp:16:60: error: type/value mismatch at argument 1 in template parameter list for ‘template class Base’
16 | void Base<std::enable_if<!std::is_integral<Q>::value>::type>::f() {
| ^
main.cpp:16:60: note: expected a type, got ‘std::enable_if<(! std::is_integral<_Tp>::value)>::type’
main.cpp:21:61: error: type/value mismatch at argument 1 in template parameter list for ‘template class Base’
21 | void Base<!std::enable_if<!std::is_integral<Q>::value>::type>::f() {
| ^
main.cpp:21:61: note: expected a type, got ‘! std::enable_if<(! std::is_integral<_Tp>::value)>::type’
main.cpp:21:6: error: redefinition of ‘template void f()’
21 | void Base<!std::enable_if<!std::is_integral<Q>::value>::type>::f() {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:16:6: note: ‘template void f()’ previously declared here
16 | void Base<std::enable_if<!std::is_integral<Q>::value>::type>::f() {
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Another alternative is if constexpr (C++17):
template<typename T>
class Base
{
public:
virtual ~Base() = default;
void f() {
if constexpr(std::is_integral<T>::value) {
std::cout << "integral\n";
} else {
std::cout << "non-integral\n";
}
}
};
Some fixes are required to your code.
First, this isn't partial specialization. If it was specialization then you could only specialize the whole class template not just one method of it.
You placed the ! in the wrong place. std::enable_if<....>::type is a type, !std::enable_if<....>::type does not make sense. You want to enable one function when std::is_integral<T>::value and the other if !std::is_integral<T>::value.
You can write two overloads like this:
#include <iostream>
using namespace std;
template<typename T>
class Base {
public:
virtual ~Base() {};
template<typename Q = T>
std::enable_if_t<std::is_integral<Q>::value> f() {
cout << "integral\n";
}
template<typename Q = T>
std::enable_if_t<!std::is_integral<Q>::value> f() {
cout << "non-integral\n";
}
};
int main()
{
Base<int> i;
i.f();
Base<std::string> s;
s.f();
return 0;
}
The SFINAE is on the return type. Q is just to have a template argument (required for SFINAE). Either std::is_integral<T>::value is true or not and only one of the two overloads is not a substitution failure. When it is not a substitution failure then std::enable_if_t< ...> is void.
SFINAE won't help you here, since f is not a template function.
You could use concepts for this though. C++20 needed for using this feature:
#include <iostream>
#include <concepts>
template<typename T>
class Base {
public:
~Base() {};
void f() requires std::integral<T>
{
std::cout << "integral\n";
}
void f() requires !std::integral<T>
{
std::cout << "non-integral\n";
}
};
These are overloads, not specializations. You need to have the two overloads in the class declaration as well, otherwise you can't write these two declarations. At that point, it's likely better to have the body of the functions inside the class declaration; SFINAE guarantees that only one of them will be active.
Consider the following code:
#include <iostream>
class S {
static const int i = 42;
template <class T>
friend void f();
};
template <class T>
void f()
{
std::cout << S::i << "\n";
}
int main()
{
f<int>();
f<double>();
}
All I want here is to allow access to private part of a class S to f<int>, but not for f<double>. I.e. I want to get compiler error like 'i' is a private member of 'S' for f<double>() line.
How to achive this?
The template instantiation is a function, so just name it: void f<int>().
You need a prior declaration, though:
[C++03: 11.4/9 | C++11/C++14: 11.3/11]: If a friend declaration appears in a local class (9.8) and the name specified is an unqualified name, a prior declaration is looked up without considering scopes that are outside the innermost enclosing non-class scope. For a friend function declaration, if there is no prior declaration, the program is ill-formed. [..]
(This wasn't the case for the friend-inside-template-declaration that you had originally, because templates are looked up a little later in the parsing process.)
Here's the finished solution:
#include <iostream>
template <class T>
void f();
class S {
static const int i = 42;
friend void f<int>();
};
template <class T>
void f()
{
std::cout << S::i << "\n";
}
int main()
{
f<int>();
f<double>();
}
Now the only error is caused by the f<double>() call.
(live demo)
You need to declare (or just define) the template function before the class S. Then you can just say that you want it to be friends with f<int>(). Like so:
template <class T> void f();
class S {
static const int i = 42;
friend void f<int>();
};
template <class T>
void f()
{
std::cout << S::i << "\n";
}
#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.
Say I have the following code in Visual Studio
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp<std::string>(12,"string");
}
Now I am attempting to covert this into GCC. Going through other questions on SO I noticed that in GCC member methods cannot be specialized if the class is not specialized. I therefore came up with this solution
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general template method";
}
};
template <>
/*static*/ void foo::foo_temp<int>(int a, int value) {
std::cout << "Hello world";
}
Now this seems to do the trick however when I include the static keyword into the statement i get the error
explicit template specialization cannot have a storage class
Now this thread talks about it but I am still confused on how I could apply that here. Any suggestions on how I can make the last method static ? Also I am still confused as to why templated methods cant be static in GCC ?
This is the visual studio code
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp<std::string>(12,"string");
}
Any suggestions on how I can make the last method static?
You can't; it's unsupported by the language.
Also I am still confused as to why templated methods cant be static in GCC?
They can; they just can't be both static and non-static. Example:
struct foo {
template<typename T>
void bar() {}
template<typename T>
static void baz() {}
};
int main() {
foo f;
f.template bar<void>();
foo::baz<void>();
}
It's very confusing to me why you must have a static specialization of a (non-static) template member function. I would seriously re-evaluate this code for sanity.
Note, to the question in the comments, it is not possible to have a template specialization of a static member function, because it is not possible to have a template specialization of a member function in this situation at all. (Use overloading instead.)
struct foo {
template<typename T, typename U>
static void bar(T, U) {}
// Error, you'd need to also specialize the class, which requires a template class, we don't have one.
// template<>
// static void bar(int, int) {}
// test.cpp:2:12: error: explicit specialization of non-template ‘foo’
// 2 | struct foo {
// | ^
// Partial specializations aren't allowed even in situations where full ones are
// template<typename U>
// static void bar<int, U>(int, U) {}
// test.cpp:14:33: error: non-class, non-variable partial specialization ‘bar<int, U>’ is not allowed
// 14 | static void bar<int, U>(int, U) {}
// | ^
// Instead just overload
template<typename U>
static void bar(int, U) {}
};
Did you try good old fashioned overloading? Don't make the static method a template at all and let overloading priority take care of picking it.
The static method isn't the problem here, the template<> declaration inside a class is the main culprit. You can't declare specialized template inside a class. you can use namespace instead:
namespace foo{
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
}
int main()
{
foo::foo_temp<int>(12,7);
}
Or you can use it inside class like this:
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp(12,"string");
f.foo_temp(12,6);
}
N.B: you should call both function (at least the second one) like f.foo_temp(a,b) instead of f.foo_temp<int>() in this case.
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();
}