default template arguments in c++ - c++

Suppose i have a function template StrCompare
template<typename T=NonCaseSenCompare>//NonCaseSenCompare is a user defined class look at the detailed code below.
int StrCompare(char* str1, char* str2)
{
...
}
now in the main function i write a line
char* str1="Zia";
char* str2="zia";
int result=StrCompare(str1,str2);
it should work because we have provided a default template argument, but it does'nt compiler gives the following error
no matching function for call to `StrCompare(char*&, char*&)'
Now the detailed code is given by
#include<iostream.h>
class CaseSenCompare
{
public:
static int isEqual(char x, char y)
{
return x==y;
}
};
class NonCaseSenCompare
{
public:
static int isEqual(char x,char y)
{
char char1=toupper(x);
char char2=toupper(y);
return char1==char2;
}
};
template<typename T=NonCaseSenCompare>
int StrCompare(char* str1, char* str2)
{
for(int i=0;i < strlen(str1)&& strlen(str2);i++)
{
if(!T::isEqual(str1[i],str2[i]))
return str1[i]-str2[i];
}
return strlen(str1)-strlen(str2);
}
main()
{
char* ptr1="Zia ur Rahman";
char* ptr2="zia ur Rahman";
int result=StrCompare(ptr1,ptr2);//compiler gives error on this line
cout<<result<<endl;
system("pause");
}
If I write
int result=StrCompare<>(ptr1,ptr2);
compiler gives the same error message.

As gf and AndreyT already wrote, you can't have default template arguments with function templates. However, if you turn your comparators into function objects, you can still use default function arguments:
template<typename Comp>
int StrCompare(char* str1, char* str2, Comp = NonCaseSenCompare())
{
...
}
You can now call StrCompare() like this
StrCompare("abc","aBc",CaseSenCompare());
or like this:
StrCompare("abc","aBc"); // uses NonCaseSenCompare
A comparator would then have to look like this:
struct CaseSenCompare {
bool operator()(char x, char y) const {return x==y;}
};
Adjust StrCompare() accordingly.

§14.1/9:
A default template-argument shall not
be specified in a function template
declaration or a function template
definition, nor in the
template-parameter-list of the
definition of a member of a class
template.
A simple work-around would be to move it into a class:
template<typename T=NonCaseSenCompare>
struct StrCompare {
static int compare(char* str1, char* str2) { /* ... */ }
};

Firstly, function templates do not support default template arguments, only class templates do.
Secondly, even when all class template parameters have default arguments, you still have to specify an empty <> to refer to that class template.

What i use is next trick;
lets say you want to have function like this
template <typename E, typename ARR_E = MyArray_t<E> > void doStuff(ARR_E array)
{
E one(1);
array.add( one );
}
you will not be allowed, but i do next way:
template <typename E, typename ARR_E = MyArray_t<E> >
class worker {
public:
/*static - as you wish */ ARR_E* parr_;
void doStuff(); /* do not make this one static also, MSVC complains */
};
template <typename E, typename ARR_E>
void worker::doStuff<E, ARR_E>::getChunks()
{
E one(1);
parr_->add( one );
}
so this way you may use it like this.
MyArray_t my_array;
worker<int> w;
w.parr_ = &arr;
w.doStuff();
as we can see no need to explicitly set second parameter.
maybe it will be useful for someone.

Related

Argument list for class template `sgl::Bag` is missing

So I am currently working on a project to make a library with all of the different data structures in C++. Here I have declared a class Bag:
template<typename Type>
class Bag
{
// ...
inline static const char* print_seperator = "\n";
public:
// ...
inline static void set_seperator(const char* new_seperator)
{
Bag::print_seperator = new_seperator;
}
}
Now this works fine, but when I try to use it in my main() function like this:
sgl::Bag::set_seperator(", ");
This shows the following error:
Argument list for class template sgl::Bag is missing
..so I gave the argument list for the class template:
sgl::Bag<int>::set_seperator(", ");
..and it works fine.
But I don't want to type that out every time. Is there any way I can overcome this?
You can use default template argument for the template type parameter Type as shown below:
//use default argument for template type parameter "Type"
template<typename Type = int>
class Bag
{
// ...
inline static const char* print_seperator = "\n";
public:
// ...
inline static void set_seperator(const char* new_seperator)
{
Bag::print_seperator = new_seperator;
}
};
int main()
{
//no need to specify int
Bag<>::set_seperator(", "); //angle bracket still needed
return 0;
}
Demo

How to define function with different templates as input

I am completely new to C++ (and Stack Overflow), so please bear with me. I am trying to create two templates and a function that takes inputs from both templates.
I have tried to make some sample code that resembles my code, and which reproduces the error. Basically I have two templates Dog and Cat, and want to create an operator function which takes an instance of Dog and Cat respectively, but I am really struggling with how to write the function header. After having spent a lot of time reading Stack Overflow posts, I have thrown in keywords 'template' and 'typename' in an attempt to make it work, but I keep getting errors. Currently the error is
candidate template ignored: couldn't infer template argument 'T'
template <class T> class Dog
{
private:
int size;
public:
Dog(int size1)
{
size = size1;
}
};
template <class T> class Cat
{
private:
int size;
public:
Cat(int size1)
{
size = size1;
}
};
template <class T> // What to write here?
typename Cat<T>::template Cat<T> operator*(typename Dog<T>::template Dog<T> m,typename Cat<T>::template Cat<T> v)
{
Cat<int> return_cat(1);
return return_cat;
}
int main(int argc, char* argv[])
{
Cat<double>::Cat<double> new_cat(2);
Dog<double>::Dog<double> new_dog(4);
Cat<double>::Cat<double> result = new_dog*new_cat; // ERROR couldn't infer template argument 'T'
return 0;
}
My question is: How should I define the function header for the operator* function to avoid any errors?
I am not sure what you were trying to do with all the scope operators. You don't need them. Simply use the proper types. I have added const references because it looked reasonable for this scenario. They are not strictly required.
template <class T>
Cat<T> operator*(const Dog<T>& m, const Cat<T>& v)
{
Cat<T> return_cat(1);
return return_cat;
}
int main(int argc, char* argv[])
{
Cat<double> new_cat(2);
Dog<double> new_dog(4);
Cat<double> result = new_dog * new_cat;
return 0;
}
I'm not sure what your intended use of operator*() is, but generally it will look something like this:
template <class T>
Cat<T> operator*(Dog<T> m, Cat<T> v)
This allows a cat and dog to be multiplied if their template class is the same.
If they are not the same (that is, cat and dog have different types), you will want something like this instead:
template <class T1, class T2>
Cat<T2> operator*(Dog<T1> m, Cat<T2> v)
This allows for cat and dog to have different types and be multiplied together.
To simplify it a little bit for easier "reading" and not "mixing" dogs with cats :), you can play with this overload
template <class T>
class Animal
{
private:
T size;
public:
Animal(T size1) {
size = size1;
}
T getSize() {
return size;
}
Animal<T> operator*(Animal<T> animal1)
{
T a = animal1.getSize();
T b = this->getSize();
Animal<T> animal = Animal<T>(a*b);
return animal;
}
};
int main(int argc, char* argv[])
{
Animal<double> cat(2);
Animal<double> dog(4);
Animal<double> result( dog*cat );
return 0;
}

How to correctly use variadic templates in C++11 with this simple example?

Using VS2013 (VC2012).
After reading many answers about variadic templates and failing with my own code, I want to ask about how to compile/achieve my example, which does not represent my whole need but in place I prefer to put in order to make it easier and cleaner for everyone to understand my point.
I preferably need a function which receives an arbitrary amount of (int, const char * tuples), and access any tuple from this list inside the function. Since I believe after reading over Internet this is not possible, I tried defining the variadic template with an arbitrary amount of a certain class which would contain the int and const char* members, and it fails.
Please note it's important I want to separate the declaration from the definition in different files:
phrases.h:
class CPhraseParamInfo { // Nothing, for easier example }
class CPhrases
{
template<class... T> void Test(T... paramsInfo);
}
phrases.cpp
template<CPhraseParamInfo...> void CPhrases::Test(CPhraseParamInfo... param)
{ // Nothing, for easier example }
Errors (translated):
error C2993: 'CPhraseParamInfo' : invalid type for the template parameter '__formal' without defined type
error C3543: 'CPhraseParamInfo': doesn't contain a parameter pack
error C2244: 'CPhrases::Test' : cannot match the function definition with an existent declaration
Remember I'd prefer the first method, if possible. I hope I was clear enough.
Thanks!
Thanks #Yakk. Here is expanded example with part of my real codework in order to show how to allow a last parameter to be used as arbritrary values passing (for certain phrase va_args processing), if anyone finds it useful. The key here is to call the variadic template function with the same amount of variadic class used on the template call list (< CPhraseParamInfo, ... >):
phrases.h:
class CPhrases:
{
template<class... ParamInfo, typename... Arg> static void
LoadForPlayer(CHL2RP_Player *player, char *dest, int maxlen, const char *header,
const char *prependText, ParamInfo&... paramsInfo, Arg... args)
{
CPhraseParamInfo paramsInfoBuff[] = { paramsInfo... };
LoadForPlayer(player, dest, maxlen, header, prependText, paramsInfoBuff, sizeof paramsInfoBuff, args...);
}
static void LoadForPlayer(CHL2RP_Player *player, char *dest, int maxlen, const char *header, const char *prependText,
CPhraseParamInfo *paramsInfoBuff, int paramCount, ...);
static FORCEINLINE void LoadRegionChat(CHL2RP_Player *player, char *dest, int maxlen, const char *talker, const char *message)
{
LoadForPlayer<CPhraseParamInfo, CPhraseParamInfo>(player, dest, maxlen, REGION_CHAT_HEADER, INDIAN_RED_CHAT_COLOR,
CPhraseParamInfo(CPhraseParamInfo::STRING, TEAM_CHAT_COLOR "%s" DEFAULT_CHAT_COLOR), CPhraseParamInfo(CPhraseParamInfo::STRING, "%s"), talker, message);
}
}
The definition of a template function must be visible at the point where it is used, barring unusual cases.
You could do this:
class CPhraseParamInfo { // Nothing, for easier example }
class CPhrases {
void Test( CPhraseParamInfo* start, CPhraseParamInfo* end );
template<class... T> void Test(T... paramsInfo) {
CPhraseParamInfo buff[]={paramsInfo...};
return Test(buff, buff+sizeof...(paramsInfo));
}
};
then in your cpp file:
void CPhrases::Test(CPhraseParamInfo* start, CPhraseParamInfo* end)
{
// Nothing, for easier example
}
or something similar.

Pointer template specialization

I'm new to templates in C++, so here is my problem.
I've a generic class ProductItem that will do all the stuff I want, but I need to specialize a part in order to use pointers (for char*).
My code :
typedef unsigned char BYTE;
template<typename T>
class TProductTableItem
{
protected:
int Offset;
int DataLength;
T Value;
public:
virtual bool LoadFromBuffer(const BYTE* buffer, int count)
{
if(Offset + DataLength > count)
return false;
Value = buffer[Offset];
return true;
}
};
// Specialization (doesn't compile)
class TProductTableItemString : public TProductTableItem<char*>
{
bool LoadFromBuffer(const BYTE* buffer, int count)
{
if(Offset + DataLength > count)
return false;
memset(Value, 0, DataLength);
memcpy(Value, (void*)&buffer[Offset], DataLength);
return true;
}
};
When trying to compile this code, I've the following error message:
cannot convert from 'const BYTE' to 'char*'
What I'm doing wrong?
It look like that even for char* type, it tries to use the TProductTableItem::LoadFromBuffer function and not the TProductTableItemString::LoadFromBuffer one.
Thanks.
TProductTableItemString, by inheriting from it, causes an instantiation of TProductTableItem<char*>. In the implementation of TProductTableItem::LoadFromBuffer, this line:
Value = buffer[Offset];
cannot be compiled because buffer[Offset] is a byte, and Value is a char*.
By the way, TProductTableItemString is not a specialization, it is simply inheriting and then hiding LoadFromBuffer. If you really want to specialize, you should write:
template<>
class TProductTableItem<char*>
{
...
};
You are mixing two distinct concepts: inheritance and template specialization.
Your class is not a template specialization but it derives from a template instantiation. However that template cannot be instantiated because when T = char * the statement Value = buffer[offset]; has a type mismatch error.
If you want to write a template specialization then the syntax is
template<>
class ProductTableItem<char *> {
...
};
Note that two templates instantiations are in general unrelated types from an inheritance point of view...
May be a solution for what you are trying to do is something like
// Non-template base class
class ProducTableItemBase {
protected:
...
public:
virtual bool LoadFromBuffer(const BYTE* buffer, int count) = 0;
};
// Template class for all other types
template<typename T>
class ProductTableItem : public ProductTableItemBase {
T Value;
bool LoadFromBuffer(const BYTE* buffer, int count) {
...
}
};
// Template specialization for char*
template<>
class ProductTableItem<char *> : public ProductTableItemBase {
char * Value;
bool LoadFromBuffer(const BYTE* buffer, int count) {
...
}
};
I said may be because indeed it's not clear to me what you are trying to accomplish.
You are confusing the concepts of inheritance and specialisation. Firstly, in order to specialise a template, you don't derive from it - you use this syntax:
template <>
class TProductTableItem<char*>
{...}
The next confusion is that you are trying to use the non-specialised member variables in the specialisation. Template specialisations are are completely seperate to the non-specialised version. For this example, you have only declared the variables Offset, DataLength and Value inside the non-specialised template. You need to add these to the specialisation if you want to have them there:
template <>
class TProductTableItem<char*>
{
int Offset;
int DataLength;
char* Value;
...
}
You want your memcpy line to be more like this:
memcpy(Value, (void*)&buffer[Offset], DataLength);
And likewise when you assign Value:
Value = (T)&buffer[Offset];

How to make this specialized function work

Here's the deal. I've looked on this forum and I didn't find the information I'm searching for or I'm probably not able to repeat it for my problem. I have a class Table which is generic and I have a class named MyString.
template <typename typeGen, int DIM>
class Table {
public:
TableauGenerique() : index_(0) { //On initialise courant à 0
}
void add(typeGen type);
private:
typeGen tableGen_[DIM];
int index_;
};
My problem is with the add function.
I sometimes have to do this in the main.cpp: (which works well)
Table <float,6> tabFloat;
tabFloat.add(1.6564);
and at one point, I need to do this which doesn't work because I need to specialize the add function to create an object of MyString, to pass it the string and then store the object in the array (tableGen) :
TableauGenerique <MyString,4> tabString;
So I tried this (after the class), without success.
template <typename typeGen, int DIM>
void Table<typeGen,DIM>::add(typeGen type){ //Which is the generic one for float or ints
if(index_ < DIM) {
tableGen_[courant_] = type;
index_++;
}
}
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type) { //(line 75) Which is the specific or specialized function for myString
MyString str(type);
if(index_ < DIM) {
tableGen_[courant_] = str;
index_++;
}
}
So, How can I make this work because it doesn't compile at all, saying: line75 : error: expected initializer before '<' token and in the main it says not matching function to call Table::add(const char[6]),
I hope everything is clear enough. Let me know if somethings is unclear.
Thank you very much for your help !
template <class typeGen, int DIM>
void Table<typeGen,DIM>::add<string>(typeGen type)
You're trying to specialize add() when in fact it is not a function template to begin with. How do you expect it to work?
You probably meant: (specialization of the class)
template <int DIM>
void Table<string,DIM>::add(string type)
But then this is allowed only if you specialize the class itself. Without specializing the class, the above code would give compilation error!
EDIT:
You can read these online tutorials:
Introduction to C++ Templates
14.5 — Class template specialization
Template Specialization and Partial Template Specialization
Explicit specialization (C++ only)
If you can control the code of the MyString class, you can provide constructors that act as implicit conversions from float to MyString. An example:
#include <string>
#include <sstream>
#include <iostream>
class MyString {
public:
MyString(float number) {
std::stringstream buffer;
buffer << number;
value = buffer.str();
}
void print() {
std::cout << value << std::endl;
}
private:
std::string value;
};
template <class T>
class Foo {
public:
void DoStuff(T item) {
item.print();
}
};
int main() {
Foo<MyString> foo;
foo.DoStuff(1.342); // implicitly converts float to MyString
return 0;
}
This way, you do not need any specialization of the add method. However, implicit conversions are tricky, and you have be careful not to invoke them accidentally, and they may create ambiguities.
EDIT: Upon a second thought, my suggestion below is basically equivalent to
Table<MyString,4> tabString;
tabString.add(MyString("whatever"));
and therefore excessive and/or does not solve the problem. Feel free to ignore :)
I would extend the class Table with a generic method to add something from which you can construct an object of the desired type:
template <typename typeGen, int DIM>
class Table {
public:
Table() : index_(0) {}
void add(typeGen type);
// The additional method
template<typename T> void add(const T& src);
private:
typeGen tableGen_[DIM];
int index_;
};
template<typename typeGen, int DIM>
template<typename T>
void Table<typeGen,DIM>::add(const T& src) {
if(index_ < DIM) {
tableGen_[courant_] = typeGen(src);
index_++;
}
}
Note construction of a temporary typeGen object before the assignment.
Assuming that MyString object can be constructed from a string literal, i.e. from const char*, you can then use it as following:
Table<MyString,4> tabString;
tabString.add("whatever");
or if the above assumption is wrong, the following should probably work (because you constructed a MyString instance from a string instance):
tabString.add(string("whatever"));