I have a base class template and a class deriving from an instantiation of it:
template<typename T>
class Bar
{
template <T t>
void Foo();
};
class Derived : public Bar<int> {};
How should one implement Derived::Foo<0>() for example?
when trying this out:
template<>
void Derived::Foo<0>() { /* impl.. */}
i get the following compile error:
template-id 'Foo<0>' for 'Derived::Foo()' does not match any template declaration.
You cannot specialize it in the descendant; you can only add a signature that'll serve as an overload and delegate as necessary:
template<typename T>
class Bar
{
template <T t>
void Foo();
};
class Derived : public Bar<int> {
using Base = Bar<int>;
template <int t>
void Foo()
{
if constexpr(t == 0) {
/* impl... */
} else {
Base::Foo<t>();
}
}
};
Since the ADL / Koenig lookup of a class does not include template base class(es), I'd not expect any issues during overload resolution if you do it this way.
Related
Assuming the following class:
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
}
How can I add another function to a specialisation of the class while not rewriting all possibly 100 functions that are already templated?
template<>
class Test<int> {
public:
void do_something_else();
}
...
int main() {
auto x = Test<int>();
x.do_something5(); // should be still valid, would call
// Test<T>::do_something5() with T being int
x.do_something_else(); // valid because declared in specialisation
...
}
Right now, if the Test<int> specialisation is left as in the example above, it would only contain do_something_else(), without do_something1...100().
Solution
Based on the accepted answer, using the given example, I did the following:
namespace parent {
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100();
}
}
template <typename T>
class Test : public parent::Test<T> {
using parent::Test<T>::Test; // inherit constructors
}
template <>
class Test<int> : public parent::Test<int> {
using parent::Test<int>::Test;
public:
void do_something_else();
}
You can create a common base class, and make both the primary template and specialization deriving from it.
Or you can make do_something_else function template and only works with int (then don't need using specialization).
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
template <typename X = T>
std::enable_if_t<std::is_same_v<X, int> && std::is_same_v<X, T>> do_something_else();
};
Or since C++20 we can use Constraints as #aschepler suggested.
template <typename T>
class Test {
public:
void do_something1();
...
void do_something100(); // basically many functions already defined
void do_something_else() requires std::is_same_v<T, int>;
};
I am trying to implement a template class that is intended to be used both as a base for deriving and for use as a concrete class if the template parameters are right.
What I want to achieve is that if a method of the template class cannot be instantiated, but a deriving class provides an implementation, that this is OK.
But if the template can be fully instantiated that the class is valid on it's own.
Example:
// interface class
class A
{
public:
virtual void foo() = 0;
virtual ~A() {}
};
// template class
template <typename T>
class B : public A
{
public:
/* if this tenplate can be instantiated */
foo()
{
T obj;
std::cout << obj;
}
/* else
foo() = 0;
*/
};
// concrete classes
// will work on it's own
typedef B<std::string> C;
class D : public B<void>
{
// B<void>::foo won't instantiate on it's own
// so we provide help here
foo() {}
};
int main(int argc, char const *argv[])
{
A * = new C(); // all good
A * = new D(); // error: cannot instantiate B<void>::foo
return 0;
}
Is there a way to achieve such an effect?
Using SFINAE, you may do something like:
namespace detail
{
// an helper for traits
template <typename T>
decltype(T{}, std::cout << T{}, std::true_type{})
helper_has_default_constructor_and_foo(int);
template <typename T>
std::false_type helper_has_default_constructor_and_foo(...);
// the traits
template <typename T>
using has_default_constructor_and_foo = decltype(helper_has_default_constructor_and_foo<T>(0));
// genaral case (so when traits is false)
template <typename T, typename = has_default_constructor_and_foo<T>>
struct C : public A {};
// specialization when traits is true
template <typename T>
struct C<T, std::true_type> : public A
{
void foo() override { std::cout << T{}; }
};
}
And finally:
template <typename T>
class B : public detail::C<T>
{
};
live demo
You could specialize for B<void>:
// template class
template <typename T>
class B : public A
{
public:
virtual void foo()
{
T obj;
std::cout << obj;
}
};
template <>
class B<void> : public A
{
public:
virtual void foo() = 0;
};
You must specialise B<> and cannot use SFINAE (on the member foo). SFINAE only works on templates, but member function templates cannot be virtual.
There are different ways you can achieve the specialization, but the most straightforward is the simple and explicit
template<typename T>
class B : public A
{
/* ... */ // not overridden foo() by default
};
template<>
class B<WhatEver> : public A
{
virtual foo();
};
I need to make a specialization of my function with template class and have problem with "illegal use of explicit template arguments".
template <typename T>
class MyClass { /* ... */ }; // it can be any template class, eg std::vector
template <typename T>
void foo() { /* ... */ } // my template function which need a specialization
template<>
void foo<int>() /* sth special for integers - it works */ }
template<template T>
void foo<MyClass<T> >() /* sth special for template class with any parameter - it doesnt work :( */ }
Of course i can type a few specialization for all MyClass'es which i need to, but maybe it can be replaced with one?
Template specialization of function is not as flexible as specialization of struct: only full specialization is allowed. If you want to do partial specialization you need to wrap your foo function inside a struct:
template <typename T> class MyClass { };
template <typename T> struct Foo;
template <typename T> struct Foo { void foo() {}};
template<> struct Foo<int> { void foo() { } };
template<typename T> struct Foo< MyClass<T> > { void foo() {} };
And then instead of calling
foo<MyClass<...>>()
you call
Foo< MyClass<...> >::foo()
You cannot partially speciallise a template function. There are discussions about removing that restriction though.
The advocated workarounds are:
Use a class template from the template function.
Wrap your function in a template class.
template <typename T>
struct foo_impl {
};
template <typename T>
void foo() {
foo_impl<T>();
}
// And now specialize foo_impl as you want:
template<>
struct foo_impl<int> {
foo_impl(){/* sth special for integers - it works */}
};
template<typename T>
struct foo_impl<myclass<T>> {
foo_impl() {/* ... */}
};
If you wanted a return-value, you should use a member-function - probably operator() - instead of the ctor.
This is a lot of extra typing, but how about:
template <typename T>
class MyClass { /* ... */ }; // it can be any template class, eg std::vector
template<typename T>
struct FooWrapper
{
static void foo()
{
// default implementation
}
};
template<typename T>
struct FooWrapper<MyClass<T>>
{
static void foo()
{
// MyClass<T> implementation
}
};
template<typename T>
void foo()
{
FooWrapper<T>::foo();
}
A possible solution could be using a base class
template<typename T> class MyClass;
class base {
private:
template<typename T> friend class MyClass;
base(); // Can't build a base object directly
};
template <typename T>
class MyClass : public base {
public:
}; // it can be any template class, eg std::vector
template <typename T>
void foo() {
} // my template function which need a specialization
template<>
void foo<int>() { /* sth special for integers - it works */ }
template<>
void foo<base>() { /* sth special for template class with any parameter - it doesnt work :( */ }
The above might also work in case you want a template parameter to your function. If you can wrap your function up I'd go with hivert's solution.
I'm writing a template <class T> array-like class A, and I want to specialize a few member functions to deal with arrays of arrays A<A<T>>.
Here is an working example that is close to what I want:
#include "stdio.h"
//primary template class
template <class T> class A {
public: void f() {printf("A<T>::f\n");}
};
//1st solution : specialization (?) of A for A<A<T>>
template <class T> class A< A<T> > {
public: void f() {printf("A<A<T>>::f\n");}
};
//2nd solution : specialization of A::f for A<A<int>>
template<> void A< A<int> >::f() {
printf("A<A<int>>::f\n");
}
int main(void) {
A<int> A_int;
A< A<int> > A_A_int;
A< A<double> > A_A_double;
A_int.f(); // ok : prints A<T>::f
A_A_int.f(); // ok : prints A<A<int>>::f
A_A_double.f(); // ok : prints A<A<T>>::f
return 0;
}
The problem with 1st solution is that I have to duplicate a lot of member functions from the primary template class
I tried to derive from the primary class but
template <class T> class A< A<T> > : public A< A<T> >
makes no sense
The problem with 2nd solution is that I have to duplicate the specialization for every possible types, and that defeats the purpose of template classes.
Since it is possible to define template<> void A< A<int> >::f(), it seems one should be able to "templatize" this specialization for any type. I tried :
template <class T> template<> void A< A<T> >::f()
template <template <class T> > void A< A<T> >::f()
template <template <> class T> void A< A<T> >::f()
and other absurd syntaxes...
So... Can I templatize the specialization template<> void A< A<int> >::f() not just for int but for any type T ?
Thanks in advance,
Best regards,
One possible way:
#include <cstdio>
// forward declaration
template<typename>
class A;
template<typename>
class A_Base {
// general case
public: void f() { printf("A<T>::f\n"); }
};
// partial specialization for any A
template<typename T>
class A_Base< A<T> > {
// special stuff
public: void f() { printf("A<A<T>>::f\n"); }
};
template<typename T>
class A : private A_Base<T> { // private inheritance, we're not modeling IS-A
public:
using A_Base<T>::f; // make f accesible
// all the other stuff that doesn't need to change
};
int main()
{
A<int> a1;
A<A<int>> a2;
a1.f(); // A<T>::f
a2.f(); // A<A<T>>::f
}
This way you put only the functions that need to behave differently in the base class. You can of course make it vice-versa - you put common code in the base class and specialize a derived class where you also define f.
Regarding CRP if I want to implement a slight variation of it (using template template parameter) I get a compile error:
template <template <typename T> class Derived>
class Base
{
public:
void CallDerived()
{
Derived* pT = static_cast<Derived*> (this);
pT->Action(); // instantiation invocation error here
}
};
template<typename T>
class Derived: public Base<Derived>
{
public:
void Action()
{
}
};
I am not exactly sure one would chose this form (that does not compile for me) instead of using this though (this works)
template <typename Derived>
class Base
{
public:
void CallDerived()
{
Derived* pT = static_cast<Derived*> (this);
pT->Action();
}
};
template<typename T>
class Derived: public Base<Derived<T>>
{
public:
void Action()
{
}
};
This should compile as well. We just need to get the other template parameter specified explicitly
template <typename T, template <typename T> class Derived>
class Base
{
public:
void CallDerived()
{
Derived<T>* pT = static_cast<Derived<T>*> (this);
pT->Action(); // instantiation invocation error here
}
};
template<typename T>
class Derived: public Base<T,Derived>
{
public:
void Action()
{
}
};
In the first example, the class template actually takes template template parameter, not just template parameter, as you've written:
template <template <typename T> class Derived>
class Base
{
//..
};
So this code doesn't make sense:
Derived* pT = static_cast<Derived*> (this);
pT->Action(); // instantiation invocation error here
Here Derived is a template template argument which needs template argument which you didn't provided to it. In fact, in the CallDerived() function, you cannot know the type you need to provide to it, in order to do what you intend to do.
The second approach is the correct solution. Use it.