The following code:
using namespace std;
template <typename X>
class Goo {};
template <typename X>
class Hoo {};
template <class A, template <typename> class B = Goo >
struct Foo {
B<A> data;
void foo1();
void foo2();
};
template <typename A>
void Foo<A>::foo1() { cout << "foo1 for Goo" << endl;}
int main() {
Foo<int> a;
a.foo1();
}
gives me a compiler error:
test.cc:18: error: invalid use of incomplete type 'struct Foo<A, Goo>'
test.cc:11: error: declaration of 'struct Foo<A, Goo>'
Why can't I partially specialize foo1() ? If this is not the way, how do I do this?
I have another question: what if I want foo2() to be defined only for A=int, B=Hoo
and not for any other combination, how do I do that?
Function templates may only be fully specialized, not partially.
Member functions of class templates are automatically function templates, and they may indeed be specialized, but only fully:
template <>
void Foo<int, Goo>::foo1() { } // OK
You can partially specialise the entire class and then define it anew:
template <typename A>
struct Foo<A, Goo>
{
// ...
};
(See 14.7.3 for details.)
The template still has two parameters, and you must write something like this:
template <typename A, template <typename> class B>
void Foo<A,B>::foo1() { cout << "foo1" << endl;}
The default has been specified, and only needs to be specified once. From then on, it's just like any other two-parameter template. This code will apply no matter what B is (defaulted or otherwise). If you then wish to specify different behaviour for a particular B, then you do specialization of the class, not just of a method.
(Heavily edited)
Related
Suppose I have a template class Foo with two template args and one template member function.
I want to make member function specialization while the template class is partial specialization, but the following code compiled failed by g++
template <typename A, typename B>
class Foo
{
public:
template<typename C> void bar();
};
template<> template<typename T> inline void Foo<T, int>::bar<float>() {
}
int main()
{
Foo<double, int> foo;
foo.bar<float>();
return 0;
}
g++ says:
error: expected initializer before ‘<’ token
template<> template inline void Foo<T, int>::bar() {
I've tried
template<typename T> template<> inline void Foo<T, int>::bar<float>() {
and g++ complains more
Can it be possible and how to make it ?
[temp.expl.spec]/17:
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well. In such an explicit specialization declaration, the keyword template followed by a template-parameter-list shall be provided instead of the template<> preceding the explicit specialization declaration of the member. The types of the template-parameters in the template-parameter-list shall be the same as those specified in the primary template definition.
In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
for your code:
template<typename A, typename B>
class Foo{
public:
template<typename C> void bar();
};
template<typename T> // for `Foo`
template<> // for `bar`
inline void Foo<T, int>::bar<float>(){}
int main(){
Foo<double, int> foo;
foo.bar<float>();
return 0;
}
it's ill-formed because bar is explicitly specialized but Foo is NOT.
As you specialize your class template, you have get a full independent class for the specialization. And as this, you have to write your class spezialisation with the function foo in it.
Example:
template <typename A, typename B>
class Foo
{
public:
template<typename C> void bar() { std::cout << "Generic" << std::endl;}
};
template <typename T>
class Foo<T,int>
{
public:
template<typename C> void bar(){ std::cout << "spezialized" << std::endl; }
};
int main()
{
Foo<double, int> foo;
foo.bar<float>();
Foo<double, char> foo2;
foo2.bar<int>();
return 0;
}
I believe you try to do something different :-)
If you want to have a specialization of a member only in a specific specialization and in non specialized cases you want to see the generic functionality of your class template, you can do it like:
Example:
class Base
{
public:
template<typename C> void bar() { std::cout << "Generic" << std::endl;}
void other() { std::cout << "Other" << std::endl; }
};
template <typename A, typename B>
class Foo: public Base
{
};
template <typename T>
class Foo<T,int>: public Base
{
public:
template<typename C> void bar(){ std::cout << "spezialized" << std::endl; }
};
int main()
{
Foo<double, int> foo;
foo.bar<float>();
foo.other();
Foo<double, char> foo2;
foo2.bar<int>();
foo2.other();
return 0;
}
So, first consider the following where template parameters are known implicitly from the function arguments:
#include <iostream>
using namespace std;
class A {};
class B {};
template <class T1, class T2>
class C {
T1 a;
T2 b;
};
template <class T1>
class D {
T1 a;
};
template <template<class, class> class TC, class TA, class TB>
void foo(TC<TA, TB> c) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(TD<TA> d){
std::cout << "T<T>" << std::endl;
};
int main() {
C<A,B> c;
D<A> d;
foo(c);
foo(d);
}
And output is as you'd expect:
T<T,T>
T<T>
However, what if I don't have an instance of class C and D so I need to explicitly call the correct overload? How would this be done? i.e., have a main() that consists of:
int main() {
foo<C<A,B> >();
foo<D<A> >();
}
I've experimented with a few overloads of foo() as shown below:
template <template<class, class> class TC>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD>
void foo(){
std::cout << "T<T>" << std::endl;
};
template <template<class, class> class TC, class TA, class TB>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(){
std::cout << "T<T>" << std::endl;
};
However, this (and all permutations I've been able to think of) simply results in a series of errors along the lines of the (abbreviated) output shown below
prog.cpp: In function 'int main()':
prog.cpp:44:18: error: no matching function for call to 'foo()'
foo<C<A,B> >();
^
prog.cpp:44:18: note: candidates are:
prog.cpp:19:6: note: template<template<class, class> class TC> void foo()
void foo() {
^
prog.cpp:19:6: note: template argument deduction/substitution failed:
prog.cpp:24:6: note: template<template<class> class TD> void foo()
void foo(){
^
prog.cpp:24:6: note: template argument deduction/substitution failed:
Is what I'm looking to do even allowable? If so, where am I messing up?
---- EDIT ----
So as apple apple pointed out if my main() is as follows:
int main() {
foo<C, A, B>();
foo<D, A>();
}
I get the output as expected.
However, my real-world case winds up being more complex. I'll expand a bit here. The legacy code has (hundreds) of typedefs defined in headers elsewhere along the lines of:
typedef C<A, B> type_117;
typedef D<A> type_252;
The class I'm working on is templated and is instantiated with one of those typedefs as the templating argument. So something along the lines of:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
where Test was instantiated as
Test<type_117> aTest;
So I've been trying to figure out how to write foo() for this context. At the point I call foo() within my Test's initializer am I able to "decompose" it to produce the <C,A,B> form? Or have I hit a roadblock and need to rework some of the existing framework?
template<class T>struct tag_t{constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
these are type tags. They can be passed to functions without an instance of the type.
Template functions will deduce on them.
template <template<class, class> class TC, class TA, class TB>
void foo(tag_t<TC<TA, TB>>) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(tag_t<TD<TA>>){
std::cout << "T<T>" << std::endl;
};
at call site do foo(tag<type_117>) and bob, as they say, is your uncle.
In C++98 (ick):
template<class T>struct tag_t{};
foo(tag_t<type_117>());
You may use partial specialization (and variadic template):
template <class Type>
class Test;
template <template <typename ...> class C, typename ... Ts>
class Test<C<Ts...>>
{
public:
Test() : mSC(foo<C, Ts...>()) {}
SomeClass mSC;
};
Take in count that partial specialization is forbidden for functions; so is difficult to do what do you exactly asked.
The suggestion from apple apple (chenge the calling as foo<C, A, B>() is a good one but, if you want to maintain the original call (foo<C<A, B>>()) you can use the fact that the partial specialization is allowed for structs/classes and create a partial specialization for a functor; something like
template <typename>
struct bar;
template <template<typename, typename> class Tc, typename Ta, typename Tb>
struct bar<Tc<Ta,Tb>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta, Tb>>()" << std::endl; }
};
template <template<typename> class Tc, typename Ta>
struct bar<Tc<Ta>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta>>()" << std::endl; }
};
The problem (?) is that, calling it, you can't call as bar<C<A,B>>() od bar<D<A>>() but you have to add a couple of parentheses:
bar<C<A,B>>()();
bar<D<A>>()();
or
bar<C<A,B>>{}();
bar<D<A>>{}();
I suppose that the functor solution can solve also the problem of the Edit part of your question.
If the added couple of parentheses is a problem, you can (as suggested by Jarod42 (thanks!)) wrap the call in a template function, as follows
template <typename T>
void bar ()
{ bar<T>{}(); }
So you can call the bar<C<A, B>>() function and manage the call in the specialized bar<C<A, B>> struct.
Observe also the solution from Jarod42: depending on your requirements, you could develop only a version of the partial specialization of bar.
-- EDIT --
The OP ask
I'm not that familiar with partial specialization; could you expand a bit on how what I was trying was?
Specialization (partial and full) is a big, big topic.
Just some example, to give an idea.
Given a template class/struct
template <typename X, typename Y>
struct foo
{ };
you can partial specialize it as follows (by example)
template <typename X>
struct foo<X, X>
{ };
when the specialization maintain a template variable, or you can full specialize as follow (by example)
template <>
struct foo<int, long>
{ };
where all template argument are fixed.
Well: with function you can full specialize but not partial specialize.
So you can write a template function
template <typename X, template Y>
void foo ()
{ }
and full specialize it
template <>
void foo<int, long> ()
{ }
but you can't partial specialize it; so you can't write (is an error)
template <typename X>
void foo<X, X> ()
{ }
I have a template that inherits from another template, with itself as the second template's template parameter. The inherited template defines a static function:
template<class T> class A
{
public:
static void foo();
};
template<class T> class B : public A<B>
{
};
Now I want to implement the static function for the class A specialized with B, but with B not specialized. But I can't figure out how to declare the template. I'm not even sure if this is possible. My first try was:
template<class T> void A<B<T>>::foo()
{
}
But this gives the error:
"Nested name specifier 'A<B<T>>::" for declaration does not refer into a class, class template or class template partial specialization"
I've tried different things like adding "template<>" in front but none of those worked. I am able to compile this:
template<> void A<B<int>>::foo()
{
}
As well as this:
template<class T> void A<T>::foo()
{
}
Is this an attempt at partial specialization? My first impression is no (there are no templates with multiple parameters where I want to specialize one of them). Rather, I want to specialize a template with another template that is not specialized. Is this possible, and if so what is the proper syntax?
This is indeed partial specialization. You cannot partially specialize just a method, you must partially specialize the whole class. See this answer. You might try implementing foo in a separate helper struct and partially specializing that struct instead.
Here is an example using a helper struct.
#include <iostream>
template<class T> struct t_helper
{
static void foo()
{
std::cout << "Not B<T>\n";
}
};
template<class T> class A
{
public:
static void foo() {
t_helper<T>::foo();
}
};
template<class T> class B {};
// Specialize the behavior of A<T>::foo() for all B types
template<class T>
struct t_helper<B<T>>
{
static void foo()
{
std::cout << "Is B<T>\n";
}
};
int main()
{
A<int>::foo(); // Prints "Not B<T>\n"
A<B<int>>::foo(); // Prints "Is B<T>\n"
return 0;
}
I'm using a template library in which class B is a templated class parametrized by class A. I have a declaration
template <class A, template <class A> class B>
void foo(){
B<A> x;
}
later on I want to invoke this as
foo<A, B>();
where X is a concrete class in the library and Y is a particular templated concrete class in the library. However, I get the titled error abour template argument deduction/substitution failed. If I change the declaration of foo to remove the templates and subsitute in X and Y, then it all works ok. I also tried
foo<X, Y<X> >();
which failed with the same message. Can someone explain why this is happening?
I'm using gcc 5.3.0
Here's a complete example which gives the indicated behavior
#include <vector>
template <class A, template <class A> class B>
void foo() {
B<A> x;
}
void bar() {
foo<int, std::vector>();
}
You have two issues that I can see.
First is that std::vector takes more than one template argument so the template template parameter template<class A> class B will never match std::vector.
Second and slightly less of an issue is that the class A here template<class A> class B shadows the previous class A here template <class A/*here*/, template <class A> class B>
To fix both of these issues you can declare the second template argument as an nameless variadic template like so: template <class...> class B.
Combining everything you get:
#include <vector>
template <class A, template <class...> class B>
void foo() {
B<A> x;
}
void bar() {
foo<int, std::vector>();
}
Edit:
If you would like to only use B in the form of B<A> you could do one of a few things:
template <class A, template <class...> class B>
void foo() {
using C = B<A>;
C x;
}
OR:
template <class A, template <class...> class B, class C = B<A>>
void foo() {
C x;
}
OR (depending on the larger point of your code) you could just accept the whole thing as one template parameter:
template <class A>
void foo() {
A x;
}
void bar() {
foo<std::vector<int>>();
}
std::vector is not templated on one class, so it does not match your type. You can coerce it to match by
template <class X> using MyVector = std::vector<X>;
and that will work. C++17 will just plain fix this to work as you expected it to.
Is there a partial specialization for template class method?
template <class A, class B>
class C
{
void foo();
}
it doesn't work to specialize it like this:
template <class A> void C<A, CObject>::foo() {};
Any help?
If you are already have specialized class you could give different implementation of foo in specialized class:
template<typename A, typename B>
class C
{
public:
void foo() { cout << "default" << endl; };
};
template<typename A>
class C<A, CObject>
{
public:
void foo() { cout << "CObject" << endl; };
};
To specialize member function in Visual C++ 2008 you could make it template too:
template<typename A, typename B>
class C
{
template<typename T>
void foo();
template<>
void foo<CObject>();
};
The solution above seems to will be available only in future C++ Standard (according to draft n2914 14.6.5.3/2).
I think there is a misunderstanding there.
There are two kinds of templates:
the template classes
the template methods
In your example, you have a template class, which of course contains some methods. In this case, you will have to specialize the class.
template <class A>
class C<A,CObject>
{
void foo() { ... } // specialized code
};
The problem in your example is relatively simple: you define the method foo for the specialization C but this specialization has never been declared beforehand.
The problem here is that you have to fully specialize your C class (and thus copying a lot of data). There are a number of workarounds.
Inheritance (Composition ?): do all the common work in a base class, then have the C class inherits and specialize as appropriate
Friend: instead of having the 'foo' method being a member of C, define it as a friend free functions and specialize only this method
Delegation: have your 'foo' method call another method 'bar', which is a free function, and specialize 'bar' appropriately
Which in code gives:
// 1- Inheritance
template <class A, class B>
class CBase
{
// Everything that does not require specialization
};
template <class A, class B>
class C: public CBase<A,B>
// depending on your need, consider using another inheritance
// or even better, composition
{
void foo(); // generic
};
template <class A>
class C<A,CObject> : public CBase<A,CObject>
{
void foo(); // specialized
};
// 2- Friend
// note the change in signature:
// - now you need to pass the attributes to be changed
// - the last parameter helps differentiating the overload
// as there is no specialization for functions
template <class A, class B> void foo(Arg1&, Arg2&, const B&);
template <class A> void foo(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
friend template <class, class> foo;
};
// 3- Delegation
// same signature as foo in (2)
template <class A, class B> void bar(Arg1&, Arg2&, const B&);
template <class A> void bar(Arg1&, Arg2&, const CObject&);
template <class A, class B>
class C
{
void foo() { bar(member1, member2, B()); }
};
Hope it clarifies, and helps!
No, there is no partial function template specialization in C++0x to be added.
As correctly mentioned above, with regards to function templates basically 2 things were done:
default template arguments were made available;
variadic templates were introduced.
So as before, workarounds should be used to "emulate" partial function templates specialization.
Since the class is the template, you need to specialize that:
template <class A>
class C<A, CObject>
{
void foo() { ... }
}
If I remember correctly, you cannot make partial template specialization for functions. Not sure whether it is included in C++0X
Update:
(Awaiting confirmation) As noted in the comments, partial template specialization of functions is possible in C++0X.
A method template may delegate to (static) methods of partially specialized classes or structs. Template parameters in the outer class are not helpful for answering the question.
class ClassWithSpecializedMethodEmulation
{
private:
template <typename A, typename B> struct Calculator;
public:
template <typename A, typename B> A evaluate(A a, B b)
{
return Calculator<A,B>::evaluate(a,b);
}
private:
template <typename A, typename B> struct Calculator
{
// Common case: multiply
static A evaluate(A a, B b)
{
return (A)(a*b);
}
};
// with double argument a do something else
template <typename B> struct Calculator<double, B>
{
static double evaluate(double a, B b)
{
return (double)(a - b);
}
};
};
In case the method requires access to class members, struct Calculator additionally must be friend of ClassWithSpecializedMethodEmulation and get a this-pointer passed.