Specialize template member inside template definition - c++

It is possible to specialize some class member function outside the template definition:
template<class A>
struct B {
void f();
};
template<>
void B<int>::f() { ... }
template<>
void B<bool>::f() { ... }
and in this case I can even omit definition of function f for a general type A.
But how to put this specializations inside the class? Like this:
template<class A>
struct B {
void f();
void f<int>() { ... }
void f<bool>() { ... }
};
What syntax should I use in this case?
EDIT:
For now the solution with fewest lines of code is to add a fake template function f definition and explicitly call it from original function f:
template<class A>
struct B {
void f() { f<A>(); }
template<class B>
void f();
template<>
void f<int>() { ... }
template<>
void f<bool>() { ... }
};

You should put the specialization on the struct:
template<>
struct B<int> {
void f() { ... }
};
template<>
struct B<bool> {
void f() { ... }
};
There is no way to specialize member functions in the same class the templated version is defined in. Either you must explicitly specialize the member function outside of the class, or specialize an entire class with the member function in it.

You can make B::f a template function within your struct:
struct B {
template <typename T>
void f();
template<>
void f<int>() { ... }
template<>
void f<bool>() { ... }
};
Edit:
According to your comment this may help you, but I've not tested if it works:
template <typename A>
struct B {
template <typename T = A>
void f() { ... }
template<>
void f<int>() { ... }
template<>
void f<bool>() { ... }
};

#include<iostream>
using namespace std;
template<class A>
class B
{
public:
void f() {
cout << "any" << endl;
}
};
template<>
class B<int>
{
public:
void f() {
cout << "int" << endl;
}
};
int main()
{
B<double> b1;
b1.f();
B<int> b2;
b2.f();
return 0;
}
Output:
any
int
Anything else is not possible.

Related

derived class as a parameter of templated function which is specialized for its base class

class Base {};
class Derived : public Base {};
class SomeClass
{
template<typename T>
static void SetContent(T* pChild, OVariant content)
{
LOG_ASSERT(0, "All classes must be specialized!. Please provide implementation for this class.");
}
};
template <>
void SomeClass::SetContent(Base* value)
{
LOG_TRACE("Yay!");
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
When I call foo.SetContent(derived), I get the Assert. Is it not possible for the derived class to use the specialization for it's base class?
You can convert a Derived* to a Base*, but I think you rather want to specialize for all T that have Base as base
#include <type_traits>
#include <iostream>
class Base {};
class Derived : public Base {};
template <typename T,typename = void>
struct impl {
void operator()(T*) {
std::cout <<"All classes must be specialized!. Please provide implementation for this class.\n";
}
};
template <typename T>
struct impl<T,std::enable_if_t<std::is_base_of_v<Base,T>>> {
void operator()(T*) {
std::cout << "Yay\n";
}
};
class SomeClass
{
public:
template<typename T>
static void SetContent(T* pChild)
{
impl<T>{}(pChild);
}
};
struct bar{};
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);
bar b;
foo.SetContent(&b);
}
Output:
Yay
All classes must be specialized!. Please provide implementation for this class.
//want it to call SomeClass::SetContent(Base* value)
Note that if the template argument is deduced, it will be deduced as Derived not as Base and the argument is Derived*. SomeClass::SetContent<Base>(&derived); would already work as expected with your code (because Derived* can be converted to Base*).
A workaround would be to have all SetContent's explicit specializations to form an overload set. You will have to do it yourself:
#include <iostream>
#include <utility>
#include <functional>
class Base {};
class Derived : public Base {};
template <class... T>
struct Overloads : T... {
Overloads(const T &... t) : T(t)... {}
using T::operator()...;
};
template <class R, class... Args>
struct FunctionP {
using F = R(Args...);
FunctionP(F *t) : t_(t) {}
R operator()(Args... args) const {
return std::invoke(t_, std::forward<Args>(args)...);
}
F *t_;
};
struct SomeClass {
template<typename T>
static void SetContent(T *x) {
Overloads o(FunctionP(&SetContentImpl<Base>)); // enumerates all the specializations here
if constexpr (std::is_invocable_v<decltype(o), T *>) {
o(x);
} else {
SetContentImpl(x);
}
}
template<typename T>
static void SetContentImpl(T *) {
std::cout << "1";
}
};
template <>
void SomeClass::SetContentImpl(Base *) {
std::cout << "2";
}
int main() {
SomeClass foo;
Derived derived;
foo.SetContent(&derived);//want it to call SomeClass::SetContent(Base* value)
return 0;
}
godbolt

Multiple inheritance with templated template

I want to do multiple inheritance via template arguments and pass reference to this in each base class, so I can call top level object's method from each base class's method. I can do it with manual inheritance, but I want to be able to do this via templates arguments.
Godbolt link
Godbolt link with manual inheritance
#include <cstdio>
template <typename T>
struct Foo {
Foo(T &t)
: t_(t) {
}
void foo() {
t_.call("foo");
}
T &t_;
};
template <typename T>
struct Bar {
Bar(T &t)
: t_(t) {
}
void bar() {
t_.call("bar");
}
T &t_;
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl>... {
Impl()
: Methods<Impl>(*this)... {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}
I tried this approach, but it gives
type/value mismatch at argument 1 in template parameter list for 'template<class> class ... Methods'
Thanks to #Nicol Bolas, he advised to use static_cast and CRTP for this
#include <cstdio>
template <typename T>
struct Foo {
void foo() {
static_cast<T*>(this)->call("foo");
}
};
template <typename T>
struct Bar {
void bar() {
static_cast<T*>(this)->call("bar");
}
};
template <template<typename> typename... Methods>
struct Impl : public Methods<Impl<Methods...>>... {
Impl() {
}
void call(const char *m) {
printf(m);
}
};
int main() {
auto t = Impl<Foo, Bar>();
t.foo();
t.bar();
}

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

Function Template Specialization Syntax aggregating templated types

With respect to function template specialization, I would like help with a bit of syntax. The following is a simplified scenario:
Base header:
template <typename T>
void Foo(T* t) { TRACE("Default Foo impl"); } // <-- default implementation
template <typename T>
struct Base
{
explicit Base()
{
static_assert(std::is_base_of<Base, T>::value, "T must derive from Base");
Foo(static_cast<T*>(this));
}
};
Derived_X header:
struct Derived_X : public Base<Derived_X>
{
explicit Derived_X() : Base<Derived_X> { } { }
};
// no specialization will be implemented --> using default
Derived_Y header:
struct Derived_Y : public Base<Derived_Y>
{
explicit Derived_Y() : Base<Derived_Y> { } { }
};
template <> // Foo specialization for Derived_Y
void Foo<Derived_Y>(Derived_Y* t)
{
Foo(static_cast<Base<Derived_Y>*>(t)); // <-- call default impl
TRACE("Derived_Y Foo impl");
}
Derived_Z header:
template <typename T>
struct Derived_Z : public Base<T>
{
explicit Derived_Z() : Base<T> { }
{
static_assert(std::is_base_of<Derived_Z, T>::value, "T must derive from Derived_Z");
}
};
/* What does this specialization look like?
template <typename T>
void Foo<Derived_Z<T>>(Derived_Z<T>* t)
{
Foo(static_cast<Base<T>*>(t)); // <-- call default impl
TRACE("Derived_Z<T> Foo impl");
}
// */
MostDerived Header:
struct MostDerived : public Derived_Z<MostDerived>
{
explicit MostDerived() : Derived_Z<MostDerived> { } { }
};
template <>
void Foo<MostDerived>(MostDerived* t)
{
Foo(static_cast<Derived_Z<MostDerived>*>(t)); // <-- call Derived_Z impl
TRACE("MostDerived Foo impl");
}
Usage:
int main()
{
Derived_X dx { }; // <-- "Default Foo impl"
Derived_Y dy { }; // <-- "Default Foo impl" && "Derived_Y Foo impl"
MostDerived md { }; // <-- "Default Foo impl" && "MostDerived Foo impl"
}
I have not been able to determine how to specialize Foo for Derived_Z. Any help would be most appreciated!
It's generally considered poor form to specialize function templates. You won't be able to partially specialize (as you have noticed), and they won't be considered in overload resolution. Rather, just create overloads, and let overload resolution take care of the rest.
// no template at all for Derived_Y
void Foo(Derived_Y* t)
{
Foo(static_cast<Base<Derived_Y>*>(t)); // <-- call default impl
TRACE("Derived_Y Foo impl");
}
// a regular template (no specialization) for Derived_Z<T>
template <typename T>
void Foo(Derived_Z<T>* t)
{
Foo(static_cast<Base<T>*>(t)); // <-- call default impl
TRACE("Derived_Z<T> Foo impl");
}
// again, no template for MostDerived
void Foo(MostDerived* t)
{
Foo(static_cast<Derived_Z<MostDerived>*>(t)); // <-- call Derived_Z impl
TRACE("MostDerived Foo impl");
}
Now, you might want to consider changing the base implementation to only accept a Base<T>* rather than a T*. Say you have Derived_Y2 that derives from Derived_Y, but you have not defined an overload for Foo(Derived_Y2*). Calling Foo() using a pointer to a Derived_Y2 will then go to Foo(T*) with T being deduced as a Derived_Y2, as that is a better match than Foo(Derived_Y*)
struct Derived_Y2 : Derived_T { };
Derived_Y2 y2; // "Default Foo impl"
By changing the base implementation to:
template<class T>
void Foo(Base<T>*) { TRACE("Default Foo impl"); }
Foo(Derived_Y*) will now be a better match when given a pointer to a Derived_Y2, because it is more specialized as they say.
I have not been able to determine how to specialize Foo for Derived_Z.
It's because you can't partial specialize a template function.
But you can partial specialize a class/struct.
So I propose the use of an helper struct
template <typename T>
struct bar
{
static void func (T *)
{ std::cout << "default bar" << std::endl; }
};
template <>
struct bar<Derived_Y>
{
static void func (Derived_Y *)
{ std::cout << "Derived_Y bar" << std::endl; }
};
template <typename T>
struct bar<Derived_Z<T>>
{
static void func (Derived_Z<T> *)
{ std::cout << "Derived_Z<T> bar" << std::endl; }
};
and Foo() simply become
template <typename T>
void Foo (T * t)
{ bar<T>::func(t); }

Invalid use of incomplete type (class method specialization)

First, I've read over many other questions and couldn't find the solution. So before marking it a duplicate, please make sure duplicate answers the question.
I'm trying to specialize F::operator() for a class C2; however, C2 has a template parameter and I want F::operator() to behave the same for all C2's.
Compiler error:
error: invalid use of incomplete type ‘struct F<C2<T> >’
void F<C2<T>>::operator()()
Also, instead of Handle& h, I tried Handle* h and received the same error.
#include<iostream>
struct C1
{
void foo()
{
std::cout << "C1 called" << std::endl;
}
};
template<typename T>
struct C2
{
void bar();
};
template<>
void C2<int>::bar()
{
std::cout << "C2<int> called" << std::endl;
}
template<typename Handle>
struct F
{
F(Handle& h_) : h(h_) {}
void operator()();
Handle& h;
};
template<>
void F<C1>::operator()()
{
h.foo();
}
template<typename T>
void F<C2<T>>::operator()()
{
h.bar();
}
int main()
{
C1 c1;
F<C1> f_c1 (c1);
f_c1();
C2<int> c2;
F<C2<int>> f_c2 (c2);
f_c2();
}
There's no such thing like a partial specialization of a member function. You'd need to first partial-specialize the entire class:
template <typename T>
struct F<C2<T>>
{
void operator()();
};
template <typename T>
void F<C2<T>>::operator()() {}
Since this is a heavy-weight solution, alternatively, you can exploit tag-dispatching:
template <typename T> struct tag {};
template <typename Handle>
struct F
{
F(Handle& h_) : h(h_) {}
void operator()()
{
call(tag<Handle>{});
}
private:
void call(tag<C1>)
{
h.foo();
}
template <typename T>
void call(tag<C2<T>>)
{
h.bar();
}
Handle& h;
};
DEMO