C++ template, static function specialization - c++

I have a syntax error with my template
I would like to partial specialize a static function of my template class
class.hpp
template <typename Foo, size_t bar = 26>
class MyClass
{
MyClass();
static void function();
};
#include "class.tpp"
class.tpp
template <typename Foo, bar>
MyClass<Foo, bar>::MyClass()
{ }
template <typename Foo>
inline
void
MyClass<Foo, 6>::function()
{
// ...
}
template <typename Foo>
inline
void
MyClass<Foo, 26>::function()
{
// ...
}
error: template definition of non-template
I just want to implement MyClass<Foo, bar>::function for bar == 26 and bar == 6
How to do that properly ?
Thanks

The function is not a template itself, it is only inside a class template. You can specialize the class for those cases, but not the function itself.
template <class Foo>
class MyClass<Foo, 26>
{
static void function() { ... }
};
Provided you have specialized the class like so, you can only declare the function inside the class, and define it outside like so:
template <class Foo>
void MyClass<Foo, 26>::function() { ... }
If you don't specialize it beforehand, you'll get a compilation error for using an incomplete type.
You might also find this question and answer on specializing a single function inside a class template relevant.

You cannot partial specialize method like that.
You may partial specialize the whole class.
or as alternative, you may forward the implementation to some helper:
struct that you may specialize as you want.
overload (using some dispatching):
namespace detail
{
template <typename Foo, std::size_t bar>
void function_impl(MyClass<Foo, bar>& that)
{
// Generic case.
}
template <typename Foo>
void function_impl(MyClass<Foo, 6>& that)
{
// special case <Foo, 6>.
}
template <typename Foo>
void function_impl(MyClass<Foo, 26>& that)
{
// special case <Foo, 26>.
}
}
template <typename Foo, std::size_t bar>
inline
void
MyClass<Foo, bar>::function()
{
detail::function_impl(*this);
}

After doing some research; Partial Specialization for member functions of a class template are not allowed, so one would have to specialize the whole class which can be a problem if the actual class is quite large. If you are trying to separate the implementation from the declaration having a wrapper or helper will work, but you must defined that and the partial specialization first. Check out this code here for it compiles, builds and outputs the appropriate values using MSVC 2015 CE.
MyClass.h
#ifndef MY_CLASS_H
#define MY_CLASS_H
#include <iostream>
// Helper - Wrapper Class
template<typename Foo, size_t Bar>
class specialized {
public:
inline static void function();
};
// Partial Specialization
template<typename Foo>
class specialization<Foo, 6> {
public:
inline static void function();
};
// Actual Class
template<typename Foo, size_t Bar = 26>
class MyClass {
private:
specialized<Foo, Bar> func;
public:
MyClass();
inline void function(); // Works
// inline static void function(); // Compiler Error
}; // MyClass
#include "MyClass.inl"
#endif // MY_CLASS_H
MyClass.inl
// Helper - Wrapper
template<typename Foo, size_t Bar>
inline void specialized<Foo, Bar>::function() {
std::cout << "26" << std::endl;
} // function
// Specialized
template<typename Foo>
inline void specialized<Foo, 6>::function() {
std::cout << "6" << std::endl;
} // function
// Constructor
template<typename Foo, size_t Bar>
MyClass<Foo, Bar>::MyClass() {
} // MyClass
// Class Member Function
template<typename Foo, size_t Bar>
inline void MyClass<Foo, Bar>::function() {
func.function();
} // function
MyClass.cpp
#include "MyClass.h"
Main.cpp
#include "MyClass.h"
int main() {
MyClass<float, 6> a;
a.function(); // Prints Out 6
MyClass<float, 26> b;
b.function(); // Prints Out 26
MyClass<float> c;
c.function(); // Prints Out 26
MyClass<float, x != 6> d;
d.function(); // Prints Out 26
return 0;
} // Main

Related

Class template, member function definition if object is of type X?

Is it possible to create a class template with a member function definition only if the object created is of a specific type?
I've created a template class I will use for storing either int or doubles, but for doubles I would like to be able to set precision too (objects created with myclass < double> should have this functionality, but for myclass< int> there is no need for that to be present at all).
I know I can use a base class template, and create new classes "myInt", "myDouble" using that and implement the functionality only in the myDouble class, but I think it would be cleaner to define the functionality (both the function and a member variable) for doubles in the class template, if that's possible and preferable?
Let's add an example to show what I want to do:
#include <iostream>
#include <iomanip>
class commonBase{
public:
void setState(int state);
virtual void print() = 0;
private:
int _my_state;
};
template <typename T>
class generalObject : public commonBase {
public:
void value(T value);
void print(){ std::cout << "My value: " << _my_value << std::endl; }
private:
T _my_value;
};
template <typename T>
void generalObject<T>::value(T value){
_my_value = value;
}
// Is there any way do specialize only only whats different from the generalObject template?
// Here I thought I could specialize the case where a generalObject is created of <double>, but
// when I do, nothing is derived from generalObject (or at least not visible as far as I can tell)
template<>
class generalObject<double>{
public:
void setPrecision(int precision){ _my_precision = precision; }
// here I would like a special implementation of print(), which overrides the print() in generalObject
// and instead also prints according to the precision set when the object is of <double> type.
// Row below an example which doesn't work (compiler error, _my_value undefined)
void print(){ std::cout << "My value: " << std::setprecision(_my_precision) << _my_value << std::endl; }
private:
int _my_precision;
};
int main(int argc, char* argv[]){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1); //inherited from the commonBase
generalObject<double> o2;
o2.setPrecision(2);
o2.value(2); //here value isn't available (compile error)
o2.print();
o2.setState(123); //also isn't available (compile error)
}
Sure.
template <typename T> class Poly;
void set_precision(Poly<double>* self, int a) {};
If you really want dot notation you can then add:
template <typename T> class Poly {
public: void set_precision(int a){::set_precision(this,a);}
...
However I think you should think about what you're trying to accomplish. If MyInt and MyDouble have different fields and different methods and different implementations, they should probably be different classes.
This can be solved using template specialization.
We first define a common template...
template< typename T >
struct myclass
{
// common stuff
};
... and specialize that for double:
template<>
struct myclass<double>
{
int precision = 10;
void setprecision( int p ){ precision = p; }
};
Now the setprecision() method can only be called for myclass<double>. The compiler will complain if we try to call it for anything else, like myclass<int>.
int main()
{
myclass<double> d;
d.setprecision( 42 ); // compiles
myclass<int> i;
i.setprecision( 42 ); // fails to compile, as expected
}
Demo.
The basic way to have a member function of a class template exist only for some template parameters is to create a specialization of the class template for those template parameters.
template<typename T>class X{
// general definition
};
template<>class X<double>{
// double-specific definition
};
The downside of this is that the specialization will need to duplicate anything that is common. One way to address this is to move the common things out to a base class template:
template<typename T>class Xcommon{
// common stuff
};
template<typename T>class X: public Xcommon<T>{
// general definition
};
template<>class X<double>: public Xcommon<double>{
// double-specific definition
};
Alternatively, you can do it the other way: put the common stuff in the derived class, and the extras in the base, and specialize the base:
template<typename T>class Xextras{
// empty by default
};
template<typename T>class X: public Xextras<T>{
// common definition
};
template<>class Xextras<double>{
// double-specific definition
};
Either way can work; which is better depends on the details.
Both these methods work for data members and member functions.
Alternatively, you can use enable_if to mean that member functions are not selected by overload resolution if the template parameter doesn't meet a required condition. This requires that the member function is itself a template.
template<typename T>class X{
template<typename U=T> // make it a template,
std::enable_if<std::is_same_v<U,double>> double_specific_function(){
// do stuff
}
};
I wouldn't recommend this option unless there is no other choice.
If the question is about a member function, then here is one of the ways to do it without class template specialization:
#include <iostream>
#include <type_traits>
template <typename T>
struct Type {
template <typename U = T,
typename = typename std::enable_if<std::is_same<U, double>::value>::type>
void only_for_double() {
std::cout << "a doubling" << std::endl;
}
};
int main() {
Type<int> n;
Type<double> d;
// n.only_for_double(); // does not compile.
d.only_for_double();
}
Example on ideone.com
If you require a data-member presence based on the template parameter, you will have to do some kind of specialization, in which case it is, probably, simpler to put the function into corresponding specialization.
EDIT: After OP made his question more specific
Here is one way to do it without extra class and getting rid of virtual functions. Hope it helps.
#include <iostream>
#include <iomanip>
template <typename T, typename Derived = void>
class commonBase {
public:
void setState(int state) {
_my_state = state;
}
void value(T value) {
_my_value = value;
}
template <typename U = Derived,
typename std::enable_if<std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
std::cout << "My value: " << _my_value << std::endl;
}
template <typename U = Derived,
typename std::enable_if<!std::is_same<U, void>::value,
void * >::type = nullptr>
void print() const {
static_cast<Derived const *>(this)->_print();
}
protected:
T _my_value;
int _my_state;
};
template <typename T>
class generalObject : public commonBase<T> {
};
template<>
class generalObject<double> : public commonBase<double, generalObject<double>> {
private:
friend commonBase<double, generalObject<double>>;
void _print() const {
std::cout << "My value: " << std::setprecision(_my_precision) <<
_my_value << std::endl;
}
public:
void setPrecision(int precision){ _my_precision = precision; }
private:
int _my_precision;
};
int main(){
generalObject<int> o1;
o1.value(1);
o1.print();
o1.setState(1);
generalObject<double> o2;
o2.setPrecision(2);
o2.value(1.234);
o2.print();
o2.setState(123);
}
Same code on ideone.com

Friend explicit specialization of function template and ADL

Why in the following the partial specialization is not selected by ADL?
template<class T>
void func1(T&){ // selected
...
}
namespace first{
template<class R>
struct foo{
friend void func1<>(foo<R>&){ // expected
cout << "foo.func1" <<endl;
}
};
}
foo<int> f;
func1(f);
Template parameters are unrelated with friend declarations. You'll need to carry them disambiguated in thefriend declaration:
template<class R>
struct foo{
template<typename U>
friend void func1<U>(foo<U>&){
cout << "foo.func1" <<endl; // cat();
}
};
Also for your case you should decide, if you want to put the friend definition inlined as above, or just provide a declaration:
template<class R>
struct foo{
template<typename U>
friend void ::func1<U>(foo<U>&);
};
The latter should match the friend template function in the global namespace explicitly, and specialization can be made as necessary:
template<>
void func1(int&){
// ...
}
template<>
void func1(std::string&){
// ...
}
// a.s.o.
You don't need to provide an specialization of func1. Just provide an overload:
namespace first {
template <class R>
struct foo {
friend void func1(foo& ){
std::cout << "foo.func1" << std::endl;
}
};
}
int i;
first::foo<int> f;
func(i); // calls ::func<int>
func1(f); // calls first::func1(first::foo<int>& );
Otherwise, you can friend a specizliation, but you can't define a specialization in the class body:
template <class R>
struct foo {
friend void func1<>(foo& ); // friends ::func1<foo<R> >
};

Use template with base class as parameter

I would like to define a template class with specialization of some methods for different types.
template <typename T>
class Handler {
public:
void method1() { method2(); }
protected:
void method2();
}
Then in the implementation file:
template <> Handler<int>::method2() { doSomething(); }
template <> Handler<float>::method2() { doSomethingElse(); }
template <> Handler<ClassB>::method2() { doSomethingDifferent(); }
So far, everything works ok.
Now I would like to define some new classes derived from ClassB, and use the template specialization on objects of these classes. Of course it compiles but does not link, because the specialization for each subclass is missing.
Is there a way to use the template for these, for example using SFINAE?
I often find overloading on a type tag a good alterantive to specialization:
namespace {
template<class T> struct Type { using type = T; }; // Or boost::type<T>
template<class T> struct TypeTag { using type = Type<T>; };
struct ClassB {};
template <typename T>
class Handler {
public:
void method1() {
method2(typename TypeTag<T>::type{}); // Call an overloaded function.
}
protected:
void method2(Type<int>) { std::printf("%s\n", __PRETTY_FUNCTION__); }
void method2(Type<float>) { std::printf("%s\n", __PRETTY_FUNCTION__); }
void method2(Type<ClassB>) { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
// Somewhere else.
struct ClassC : ClassB {};
template<> struct TypeTag<ClassC> { using type = Type<ClassB>; };
} // namespace
int main(int ac, char**) {
Handler<ClassB> b;
b.method1();
Handler<ClassC> c;
c.method1();
}
Outputs:
void {anonymous}::Handler<T>::method2({anonymous}::Type<{anonymous}::ClassB>) [with T = {anonymous}::ClassB]
void {anonymous}::Handler<T>::method2({anonymous}::Type<{anonymous}::ClassB>) [with T = {anonymous}::ClassC]
First:
template <class T,class=void>
class Handler
then use SFINAE to create a specialization:
template <class T>
class Handler<T,std::enable_if_t<test>>
Now, have that specialization either include its implementation in its body, or inherit from an implementation type (non-template) and implement that in the impl file.
For your puroposes, the test might be is base of.
Your int impl now needs a ,void parameter added.
You can also use a traits class to do conditional mapping.

explicit instantiation after specialization

#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.

Calling a templated member of a class

I've written a class that has a templated member function, mostly because it takes a std::vector as an argument, however I'm struggling to find a proper way to call it.
class foo(){
// ...
template <typename _t> int bar(const std::vector<_t> *values);
// ...
}
when calling this function later with:
// ...
foo c;
std::vector<int> v(5,100);
c.bar(&v);
// ...
I get the error:
error: no matching function for call to ‘foo::bar(std::vector<int>*)’
c.bar(&v);
Shouldn't foo::bar(std::vector<int>*) conform to the template parameters? Why won't it compile?
Working example:
#include <vector>
class foo{
public:
template <typename _t> int bar(const std::vector<_t> *values) {
return 1;
}
};
int main() {
foo c;
std::vector<int> v(5,100);
c.bar(&v);
}
If you really need it to not to be inline you can:
//from here
#include <vector>
class foo{
public:
template <typename _t> int bar(const std::vector<_t> *values);
};
template <typename _t> int foo::bar(const std::vector<_t> *values) {
return 0;
}
//to here - should be in header file to allow compiler to link it!
int main() {
foo c;
std::vector<int> v(5,100);
c.bar(&v);
}