Suppose I have a class template Foo:
template<typename T, typename U>
struct Foo {
~Foo() = default;
// I want to reuse these methods for all instantiations of Foo
void bar() {}
void poi() {}
};
I want to specialize the destructor for any Foo<T, int>, but I want Foo<T, int> to share the other member functions with the general instantiations. But if I try to do:
template<typename T>
Foo<T, int>::~Foo()
{}
outside the class, it doesn't compile, the error being "invalid use of incomplete type struct Foo<T, int>". What does this error mean, and how can I achieve what I'm trying to do?
It is not possible to partially specialise a (non-templated) member function. You need to specialise the whole class.
One way to do what you want is to inherit the common functions.
template<typename T, typename U> struct MemberProvider
{
~MemberProvider() = default;
void bar() {};
void poi() {};
};
template<typename T, typename U>
struct Foo : public MemberProvider<T, U>
{
~Foo() = default;
// Optionally, you can still do this.
// However, note that these HIDE the inherited functions
void bar() {};
void poi() {};
};
template<typename T> struct Foo<T, int> : public MemberProvider<T, int>
{
~Foo() {};
};
Note you will also need to include any members acted on by the common functions in the inherited class.
However, I would suggest the above represents a code smell. If I saw code like the above in a production environment, I'd be contemplating the presence of a design flaw. Bear in mind that, when destructing such a class, the most derived destructor is invoked before base class destructors. MemberProvider is also not a polymorphic base.
You can explicitly specialize member functions of class templates, but you cannot partially specialize them - which is what you're trying to do.
If you need to partially specialize the destructor in a way that keeps the generic version defaulted, you'll have to partially specialize the whole class template:
template <class T, class U>
struct FooCommon {
~FooCommon() = default;
void bar() {}
void poi() {}
};
template <class T, class U>
struct Foo : FooCommon<T, U> { };
template <class T>
struct Foo<T, int> : FooCommon<T, int> {
~Foo() {
// special logic here
}
};
If foo and poi do things that depend on the template parameters, then you could extract your specialised destructor behaviour into a separate class, e.g.,
#include <iostream>
template <typename T, typename U>
struct Foo;
template <typename T, typename U>
struct FooDestructorTraits
{
static void destroy(Foo<T, U> * ptr)
{
std::cout << "default" << std::endl;
}
};
template <typename U>
struct FooDestructorTraits<int, U>
{
static void destroy(Foo<int, U> * ptr)
{
std::cout << "special" << std::endl;
}
};
template <typename T, typename U>
struct Foo
{
~Foo() noexcept { FooDestructorTraits<T, U>::destroy(this); }
void bar() {}
void baz() {}
};
int main() {
Foo<void, void> x;
Foo<int, void> y;
}
Related
Basically what I'm thinking about is:
template<typename... Types>
class Foo
{
void Bar(Types var) {};...
};
which when specialized like this:
Foo<S1, S2, S3> foo;
to expand to:
class Foo
{
void Bar(S1 var){};
void Bar(S2 var){};
void Bar(S3 var){};
};
Obviously, it does not make sense in some way but I'll be happy to see some thoughts.
template<class D, class T>
struct FooHelper {
void Bar(T var) {
auto* self=static_cast<D*>(this);
// here use self instead of this
};
};
template<typename... Types>
class Foo: FooHelper<Foo,Types>...
{
template<class D,class T>
friend struct FooHelper<D,T>;
};
this is how you do what you want to do.
We use use the CRTP to give the base class access to everything in Foo.
Here's a nice C++17 way to do that:
template<typename T>
struct HelpFoo {
void Bar(T) {}
};
template<typename... Types>
struct Foo : HelpFoo<Types>...
{
using HelpFoo<Types>::Bar...;
};
You can let your methods be templated, and use enable_if to enable those in the pack list:
#include <type_traits>
template<class... Ts>
struct foo {
template<class T, std::enable_if_t<
std::disjunction_v<std::is_same<T, Ts>...>, int> = 0>
void bar(T);
};
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}
I'd appreciate help specializing the method doIt() in the following bit of code for classes that share a common base class, as shown below
#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
struct BarBase {};
struct Bar: BarBase {};
struct FooBase {};
struct Foo: FooBase {};
template <typename T>
struct Task
{
// I'd like to specialize this method for classes with a common base class
void doIt();
};
// my attempt (does not compile)
template <typename T>
typename boost::enable_if<boost::is_base_of<FooBase, T> >::value
doIt() {
std::cout << "Type is derived from FooBase\n";
}
int main()
{
Task<Foo> f;
f.doIt();
}
You can't specialise a template class member. You can specialise a class, and every specialisation is a complete separate class that inherits nothing from the unspecialised template (it may or may not have all or some of the members of the unspecialised class).
What you can also do is have a template member function in a template class, and specialise that. So you can do this:
template <typename T>
struct Task
{
void doIt() { doItPriv<T>(); }
private:
template<typename T1>
void doItPriv();
};
and then specialise doItPriv.
According to this answer,
SFINAE only works if substitution in argument deduction of a template
argument makes the construct ill-formed.
That is why you cannot do smth like that:
template <typename T>
struct Task
{
typename std::enable_if<std::is_base_of<FooBase, T>::value>::type doIt() {
std::cout << "Type is derived from FooBase\n";
}
typename std::enable_if<std::is_base_of<FooBase, T>::value == false>::type doIt()
{
}
};
Here doIt() isn't template, so no any deduction.
But you can do the following:
template <typename T1>
struct Task
{
template <typename T>
typename std::enable_if<std::is_base_of<FooBase, T>::value>::type doIt_() {
std::cout << "Type is derived from FooBase\n";
}
template <typename T>
typename std::enable_if<std::is_base_of<FooBase, T>::value == false>::type doIt_()
{
}
void doIt()
{
doIt_<T1>();
}
};
I'm writing a set of C++ parameterized classes and I'm interested in some of them behaving similarly to pointers. In particular, I want to be able to create an object with a constant template parameter from an object with a non-constant template parameter, but not the other way around. This sample code should clarify my intentions:
int main() {
myClass<int> mc_int;
myClass<const int> mc_const_int;
myClass<const int> mc1(mc_const_int); // This should compile.
myClass<int> mc2(mc_int); // This should compile.
myClass<const int> mc3(mc_int); // This should compile.
myClass<int> mc4(mc_const_int); // This should NOT compile.
}
I have been able to achieve this particular behavior by creating the next class hierarchy (simplified for readability):
template <typename T>
class Base {
// ...
protected:
template <typename U>
Base(const Base<U> &obj): _elem(obj._elem) {}
private:
T _elem;
friend class Base<const T>;
};
template <typename T>
class myClass: public Base<T> {
// ...
public:
template <typename U>
myClass(const myClass<U> &obj): Base<const U>(obj) {}
};
And it works as expected, but I'm not entirely satisfied with this design because I can only detect a non-constant template parameter from the constructor, but not from any other member function.
If I wanted, for example, to create a container class with an addAll() method, I would like to be able to do this:
int main() {
Container<int> c_int;
c_int.add(new int(1));
c_int.add(new int(2));
c_int.add(new int(3));
Container<const int> c_const_int;
c_const_int.addAll(c_int); // This should compile.
c_int.addAll(c_const_int); // This should NOT compile.
}
But I don't know how to achieve the previous behavior. Does anyone have ideas for an alternate design to achieve what I'm trying to do? Does anyone know of a link where this problem is discussed in more depth?
Thanks in advance.
One way to do this is via partial template specialisation. You should define the class for non-const types as you usually would:
template <typename T>
struct MyClass {
void f(T&);
};
Then define a specialisation
template <typename T>
struct MyClass<T const> {
void f(T&);
void f(T const&);
};
Unfortunately, this leads to code duplication, but it should allow you to do what you want. Naturally, you can have the functions take MyClass<T>& and MyClass<T const>&, too.
I'm kind of understand the question a bit. You probably can use template specialization.
template <typename T>
class container
{
public:
template<typename U>
void addAll(const container<U>& b ){}
private:
template<>
void addAll(const container<int>&b); //No implementation
};
container<int> b;
....
container<const int> a;
a.addAll(b) ; //Give a link error, I can't understand why vc2010 compile and run this line though
One possibility is using member function templates, enabling them so as to achieve the combinations you want.
#include <utility>
template <class T, class U>
struct const_convertible;
template <class T>
struct const_convertible<T, T>: std::true_type {};
template <class T>
struct const_convertible<T, const T>: std::true_type {};
template <class T>
struct const_convertible<const T, T>: std::false_type {};
template <class T>
class X
{
public:
X() {}
X(const X&) {} //copy constructor
//conversion constructor as needed
template <class U>
X(const X<U>&, typename std::enable_if<const_convertible<U, T>::value, void>::type* = 0)
{}
template <class U>
typename std::enable_if<const_convertible<U, T>::value, void>::type f(X<U>) {}
};
int main()
{
X<int> mut;
X<const int> con;
X<int> a(mut);
//X<int> b(con);
X<const int> c(mut);
X<const int> d(con);
mut.f(mut);
//mut.f(con);
con.f(mut);
con.f(con);
//X<double> doub;
//doub.f(mut);
}
Is it possible to specialize particular members of a template class? Something like:
template <typename T,bool B>
struct X
{
void Specialized();
};
template <typename T>
void X<T,true>::Specialized()
{
...
}
template <typename T>
void X<T,false>::Specialized()
{
...
}
Ofcourse, this code isn't valid.
You can only specialize it explicitly by providing all template arguments. No partial specialization for member functions of class templates is allowed.
template <typename T,bool B>
struct X
{
void Specialized();
};
// works
template <>
void X<int,true>::Specialized()
{
...
}
A work around is to introduce overloaded functions, which have the benefit of still being in the same class, and so they have the same access to member variables, functions and stuffs
// "maps" a bool value to a struct type
template<bool B> struct i2t { };
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl(i2t<B>()); }
private:
void SpecializedImpl(i2t<true>) {
// ...
}
void SpecializedImpl(i2t<false>) {
// ...
}
};
Note that by passing along to the overloaded functions and pushing the template parameters into a function parameter, you may arbitrary "specialize" your functions, and may also templatize them as needed. Another common technique is to defer to a class template defined separately
template<typename T, bool B>
struct SpecializedImpl;
template<typename T>
struct SpecializedImpl<T, true> {
static void call() {
// ...
}
};
template<typename T>
struct SpecializedImpl<T, false> {
static void call() {
// ...
}
};
template <typename T,bool B>
struct X
{
void Specialized() { SpecializedImpl<T, B>::call(); }
};
I find that usually requires more code and i find the function overload easier to handle, while others prefer the defer to class template way. In the end it's a matter of taste. In this case, you could have put that other template inside X too as a nested template - in other cases where you explicitly specialize instead of only partially, then you can't do that, because you can place explicit specializations only at namespace scope, not into class scope.
You could also create such a SpecializedImpl template just for purpose of function overloading (it then works similar to our i2t of before), as the following variant demonstrates which leaves the first parameter variable too (so you may call it with other types - not just with the current instantiation's template parameters)
template <typename T,bool B>
struct X
{
private:
// maps a type and non-type parameter to a struct type
template<typename T, bool B>
struct SpecializedImpl { };
public:
void Specialized() { Specialized(SpecializedImpl<T, B>()); }
private:
template<typename U>
void Specialized(SpecializedImpl<U, true>) {
// ...
}
template<typename U>
void Specialized(SpecializedImpl<U, false>) {
// ...
}
};
I think sometimes, deferring to another template is better (when it comes to such cases as arrays and pointers, overloading can tricky and just forwarding to a class template has been easier for me then), and sometimes just overloading within the template is better - especially if you really forward function arguments and if you touch the classes' member variables.
This is what I came up with, not so bad :)
//The generic template is by default 'flag == false'
template <class Type, bool flag>
struct something
{
void doSomething()
{
std::cout << "something. flag == false";
}
};
template <class Type>
struct something<Type, true> : public something<Type, false>
{
void doSomething() // override original dosomething!
{
std::cout << "something. flag == true";
}
};
int main()
{
something<int, false> falseSomething;
something<int, true> trueSomething;
falseSomething.doSomething();
trueSomething.doSomething();
}