C++: Non generic method in generic class? - c++

I am interested in defining a custom method for a generic class for only a particular data type. I am not sure whats a good way to implement it. I won't be able to access class variables if I place it outside the class so I think i can never get it to work that way. If i place it inside the class, its meant to work for any type T and not just the particular type. I have been able to get my code to work the latter way by just defining a generic version of it and sending only that type as input which i m interested in but is there a neater way to accomplish this?
Below is some code to make it clear
#include<iostream>
#include<string>
using namespace std;
template<typename T>
class abc
{
public:
void myvoid();
};
template<typename string>
void abc<string>::myvoid()
{
cout<<"This portion should execute only if an instance of class is called with a string parameter" ;
}
int main()
{
abc<int> int1;
abc<string> string1;
string1.myvoid(); //should work good
int1.myvoid(); //shouldnt execute myvoid
}

You can use static_assert to prevent compilation if the method in question is used with the wrong type:
#include <type_traits> // for std::is_same
template <typename T>
struct Foo
{
void foo() const {}
void bar() const
{
static_assert(std::is_same<T, int>::value, "T is not int");
}
};
int main()
{
Foo<double> fd;
fd.foo(); // OK
//fd.bar(); // ERROR: bar() only works with Foo<int>
Foo<int> fi;
fi.foo(); // OK
fi.bar(); // OK
}
Alternatively, you can use SFINAE to control the types for which the method in question exists.
template <typename T>
class Foo
{
public:
void foo() const {}
template<typename T2 = T,
typename = typename std::enable_if<std::is_same<T, int>::value>::type>
void bar() {}
};
See this related question.

This will give a linker error if you try to call bar() on a non-specialized type. This works on gcc 4.8 (see: http://ideone.com/KbwToR)
#include <iostream>
using namespace std;
struct Foo
{
template <class T>
void bar(T);
};
template<>
void Foo::bar<int>(int i)
{
cout << i << '\n';
}
int main()
{
Foo f;
f.bar(1);
f.bar("Fail!");
return 0;
}

Related

How does one specialize a template for all non-array types?

Let's say I have a template my_type. I want it to have general functionality, to have a few extra functions when T is not an array and to have others when T is an array.
Let's say I have the following template:
template <typename T>
class my_class<T> {
public:
int f1(); // This function is available for all T
int f2(); // This function is available when T is not an array
int f3(); // This function is available when T is an array
}
So if I try:
my_class<int> c1; my_class<int[3]> c2;
c1.f1(); c2.f1(); // both fine
c1.f2(); c2.f3(); // both fine
c1.f3(); c2.f2(); // both should give a compile error
I am aware std::unique_ptr does this internally. So how does it do it?
Another way, using enable_if. Note also the use of a base class to capture all common behaviour.
#include <type_traits>
template<class T>
struct my_base
{
int f1();
};
template<class T, typename Enable = void>
class my_class;
template<class T>
class my_class<T, std::enable_if_t<std::is_array<T>::value>>
: public my_base<T>
{
public:
int f3(); // This function is available when T is an array
};
template <typename T>
class my_class<T, std::enable_if_t<not std::is_array<T>::value>>
: public my_base<T>
{
public:
int f2(); // This function is available when T is not an array
};
int main()
{
auto a = my_class<int[]>();
a.f1();
// a.f2();
a.f3();
auto na = my_class<int>();
na.f1();
na.f2();
// na.f3();
}
I have figured it out myself. The following code will do the exact thing I have asked for.
template<typename T>
class my_class {
public:
int f1() { return 1; }
int f2() { return 2; }
};
template<typename T>
class my_class<T[]> {
public:
int f1() { return 1; }
int f3() { return 3; }
};
Note that the implementation of the common function (f1) had to be copied. Now is there a way to use a single implementation? (note that it is NOT as simple as a return 1; like in the example code and thus I can't separate functionality into a non-template function)

How do I format my function to call a templated class?

I'm sure there is a very easy answer, but I can't figure it out. I have written a templated class, but I want to pass that class by reference in a class function that isn't templated. Heres what I have. I get a bunch of errors. All I need to do is figure how to format the way to insert templated class into function, but I'm at a lost. Thank you and sorry if the code doesn't really help you out.
#include <iostream>
using namespace std;
template <typename T>
class Foo {
public:
Foo();
insert(const T& Item)
//And other function, just examples
};
class noFoo(){
void test(Foo <T>& foo);
int i;
int j;
int k
};
template <typename T>
void noFoo::test(Food <T>& foo)}
cout << "hi";
}
int main() {
Foo<char> wr;
test(wr);
return 0;
}
Make test a function template. I also corrected loads of syntax errors for you (class noFoo()?), removed unnecessary code, and ran clang-format for indentation.
#include <iostream>
template <typename T>
class Foo {};
class noFoo
{
public:
template <typename T>
void test(Foo<T> &);
};
template <typename T>
void noFoo::test(Foo<T> &)
{
std::cout << "hi\n";
}
int main()
{
Foo<char> wr;
noFoo{}.test(wr);
}
Since your question is tagged d, here the same code in D.
import std.stdio;
class Foo(T) {};
class noFoo
{
public:
void test(T)(Foo!(T))
{
writeln("hi");
}
};
void main()
{
auto wr = new Foo!char;
(new noFoo).test(wr);
}

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

c++ unordered map using templates

I am trying to declare an unordered map using templates in c++. However, as I expect the object to be one of the primitive datatypes I don't want to declare a custom class for only one object.
I've tried using :
template <class T> std::unordered_map<int, T> storedObj;
but I keep getting the error: ‘storedObj’ was not declared in this scope
a code snippet is below
#include<iostream>
#include<unordered_map>
#include<deque>
std::deque<int> freeIds;
template <class T> std::unordered_map<int, T> storedObj;
unsigned static int objIdCount=0;
const unsigned long int MAXID = 1000000000;
Can you please tell me what's wrong? Thanks.
You are doing partial template specialisation here (see http://en.cppreference.com/w/cpp/language/partial_specialization). Probably what you had in mind is a typedef-like construction but that doesn't work with templates.
With partial template specialisation you can (partially) re-implement or re-define a templated type.
One way to achieve your goal could be:
template <class T>
class my_unordered_map :
public std::unordered_map<int, T>
{
};
int main( void ) {
my_unordered_map<float> mf;
return 0;
}
Templates are used for compile-time polymorphism. You cannot instantiate a template-based class without specifying an actual datatype for that template.
A basic way to use templates would be:
#include <iostream>
using namespace std;
template <class T>
class MyClass {
T foo;
public:
MyClass(T bar) {
foo = bar;
}
void print() {
cout << foo;
}
};
int main() {
MyClass<int> c(5);
c.print(); // prints 5
return 0;
}
You can achieve what you're trying to do by extending (deriving) the unordered_map class, like this:
#include <iostream>
#include <unordered_map>
using namespace std;
template <class T>
class MyClass: public unordered_map<int, T> {
// optional extra code here
};
int main() {
MyClass<string> cstring;
cstring[0] = "foo";
cout << cstring[0] << "\n"; // prints "foo"
MyClass<double> cdouble;
cdouble[0] = 3.14; // prints 3.14
cout << cdouble[0];
return 0;
}

Explicit template specialization cannot have a storage class - member method specialization

Say I have the following code in Visual Studio
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp<std::string>(12,"string");
}
Now I am attempting to covert this into GCC. Going through other questions on SO I noticed that in GCC member methods cannot be specialized if the class is not specialized. I therefore came up with this solution
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general template method";
}
};
template <>
/*static*/ void foo::foo_temp<int>(int a, int value) {
std::cout << "Hello world";
}
Now this seems to do the trick however when I include the static keyword into the statement i get the error
explicit template specialization cannot have a storage class
Now this thread talks about it but I am still confused on how I could apply that here. Any suggestions on how I can make the last method static ? Also I am still confused as to why templated methods cant be static in GCC ?
This is the visual studio code
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp<std::string>(12,"string");
}
Any suggestions on how I can make the last method static?
You can't; it's unsupported by the language.
Also I am still confused as to why templated methods cant be static in GCC?
They can; they just can't be both static and non-static. Example:
struct foo {
template<typename T>
void bar() {}
template<typename T>
static void baz() {}
};
int main() {
foo f;
f.template bar<void>();
foo::baz<void>();
}
It's very confusing to me why you must have a static specialization of a (non-static) template member function. I would seriously re-evaluate this code for sanity.
Note, to the question in the comments, it is not possible to have a template specialization of a static member function, because it is not possible to have a template specialization of a member function in this situation at all. (Use overloading instead.)
struct foo {
template<typename T, typename U>
static void bar(T, U) {}
// Error, you'd need to also specialize the class, which requires a template class, we don't have one.
// template<>
// static void bar(int, int) {}
// test.cpp:2:12: error: explicit specialization of non-template ‘foo’
// 2 | struct foo {
// | ^
// Partial specializations aren't allowed even in situations where full ones are
// template<typename U>
// static void bar<int, U>(int, U) {}
// test.cpp:14:33: error: non-class, non-variable partial specialization ‘bar<int, U>’ is not allowed
// 14 | static void bar<int, U>(int, U) {}
// | ^
// Instead just overload
template<typename U>
static void bar(int, U) {}
};
Did you try good old fashioned overloading? Don't make the static method a template at all and let overloading priority take care of picking it.
The static method isn't the problem here, the template<> declaration inside a class is the main culprit. You can't declare specialized template inside a class. you can use namespace instead:
namespace foo{
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
template<>
void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
}
int main()
{
foo::foo_temp<int>(12,7);
}
Or you can use it inside class like this:
class foo
{
public:
template<typename t>
void foo_temp(int a , t s_)
{
std::cout << "This is general tmeplate method";
}
static void foo_temp(int a , int s)
{
std::cout << "This is a specialized method";
}
};
int main()
{
foo f;
f.foo_temp(12,"string");
f.foo_temp(12,6);
}
N.B: you should call both function (at least the second one) like f.foo_temp(a,b) instead of f.foo_temp<int>() in this case.