I am currently getting into templates and I am trying to fully specialize a class function here in my class (only relevant code):
class item_t
{
public:
template<class T>
void set(const std::string &key, const T &value);
template<>
void set(const std::string &key, const std::string &value);
};
which will result in this compiler error (gcc 6.3.0):
Fehler: explicit specialization in non-namespace scope ‘class base::data::item_t’
template<>
^
What am I missing here? From what I understood, it is not possible to partially specialize a function template, but this is a full specialization.
You cannot explicitly specialize a template member function inside the class definition. You have to do it outside (in a namespace scope):
class item_t
{
public:
template<class T>
void set(const std::string &key, const T &value);
};
template<>
void item_t::set<std::string>(const std::string &key, const std::string &value)
{
}
In your particular use case, you don't even need a specialization - an overload will work just fine:
template<class T>
void set(const std::string &key, const T &value);
void set(const std::string &key, const std::string &value);
Related
I have some code that reads a file and finds out whether it's Unicode or not. Depending on this I'd like to have a custom object that will hold the file contents as wstring or string and be able to do string manipulation.
I thought I could just have a base class with two derived classes representing wide and narrow strings or even a base class for string and one derived for wstring. Something like:
class CustomString
{
public:
static CustomString *methodFactory(bool _unicode);
std::string Value;
}
class NarrowString : public CustomString
{
public:
SingleByte(std::string _value);
std::string Value;
}
class WideString : public CustomString
{
public:
WideString (std::wstring _value);
std::wstring Value
}
What I'm having more difficulty with is the string manipulation methods, say I need .replace, .length and .substr how could I implement these? Would I need to use templates?
virtual T replace(size_t _pos, size_t _len, const T& _str);
Or have two methods for each type and override them in the derived classes?
virtual std::string replace(size_t _pos, size_t _len, const std::string& _str)
virtual std::wstring replace(size_t _pos, size_t _len, const std::wstring& _str)
An example of what the interface would look like using templates and no inheritance:
class CustomString
{
public:
CustomString();
CustomString(bool _unicode);
template <typename T>
T get();
template <typename T>
T replace(size_t _pos, size_t _len, const T& _str);
long length();
template <typename T>
T substr(size_t _off);
template <typename T>
T append(const T& _str);
template <typename T>
T c_str();
private:
std::wstring wValue;
std::string nValue;
bool unicode;
};
}
I suggest doing it in different form:
enum class Encoding{
UTF8,
UTF16
};
Encoding readFile(const char* path, std::string& utf8Result,std::wstring& utf16result);
now read the file to the correct object and return the correct encoding as result.
the use of this function can write generic code around this function with template generelization around std::basic_string:
template <class T>
void doNext(const std::basic_string<T>& result){/*...*/}
std::string possibleUTF8Result;
std::wstring possibleUTF16Result;
auto res = readFile("text.txt",possibleUTF8Result,possibleUTF16Result);
if (res == Encoding::UTF8){
doNext(possibleUTF8Result);
} else { doNext(possibleUTF16Result); }
*note: wstring is utf16 on windows but utf32 on linux.
I'm learning about templates in C++. In MyClass.h:
template <class valueType>
void valueToMap(const std::string key, const valueType value);
In MyClass.cpp:
void MyClass::valueToMap(const std::string key, const valueType value) // error
^
{
_map[key] = std::to_string(value);
}
The error is: Unknown type name 'valueType'
I've included the header file, so what am I doing wrong?
It needs to be a template nonetheless
template <typename valueType>
void MyClass<valueType>::valueToMap(const std::string key, const valueType value) // error
^
{
_map[key] = std::to_string(value);
}
However Keep in mind:
Why can templates only be implemented in the header file?
You need to repeat the template during both in declaration and in definition:
template <class valueType>
void MyClass::valueToMap(const std::string key, const valueType value)
{
_map[key] = std::to_string(value);
}
You should add
template <class valueType>
also before method implementation and change
void MyClass:: ...
to
void MyClass<valueType>:: ...
When dealing with templates, you cannot separate the class declaration and class implementation into separate files (at least not without including the .cpp file at the end of the .h file). This is due to how templates are compiled.
The simplest ways to do what you are trying to do is to either inline your functions:
template <class valueType> // assuming this is also at the class level
void valueToMap(const std::string key, const valueType value)
{
_map[key] = std::to_string(value);
}
Or place the implementation after the class declaration in the header file:
template<class valueType>
class MyClass
{
public:
void valueToMap(const std::string key, const valueType value);
};
template<class valueType>
void MyClass<valueType>::valueToMap(const std::string key, const valueType value)
{
_map[key] = std::to_string(value);
}
I've this code:
class XMLNode
{
//...
template <typename T>
bool getValue(T& t, const std::string& path) const
{
if (empty())
{
throw std::runtime_error("Empty node");
}
return nsXML::getValue(t, path, *node);
}
template <typename T>
T getValue(const std::string& path) const
{
if (empty())
{
throw std::runtime_error("Empty node");
}
return nsXML::getValue<T>(path, *node);
}
//...
};
class XMLData
{
//...
template <typename T>
T getValue(const std::string& path)
{
return XMLNode(&mDocNode, 0).getValue(path); // ERROR LINE
}
//...
};
And gives me error
no matching function for call to ‘nsXML::XMLNode::getValue(const string&)’
note: candidates are:
note: template<class T> bool nsXML::XMLNode::getValue(T&, const string&) const
note: template<class T> T nsXML::XMLNode::getValue(const string&) const
Why does g++ give me this error?
The compiler has no way to assess with which type you want to instantiate the function template. In this case you have to specify it explicitly:
return XMLNode(&mDocNode, 0).getValue<T>(path);
// ^-- explicit instantiation
Only in some cases the template argument can be deduced by the compiler automatically from the function arguments:
int i;
bool b = XMLNode(&mDocNode, 0).getValue(i, path);
Here, the compiler sees an int as the first function argument and can deduce T for this function call to be int, so its the same as
bool b = XMLNode(&mDocNode, 0).getValue<int>(i, path);
because your XMLNode::getValue(const std::string& path) function is a const, so when it's calling nsXML::getValue, it's looking for the const version, I guess there isn't a const one defined.
Note a const member function and a non const member function are different.
I have template with overloaded method. I'm trying to create pointer to the overloaded method.
template<typename T>
class Future {
public:
const T& get() const;
bool get(T*, int timeoutMs) const;
};
...
const void*&(Future<void*>::*x)()const = &Future<void*>::get;
Compilation fails with this error:
no matches converting function 'get' to type 'const void*& (class Future<void*>::*)()const'
candidates are: const T& Future<T>::get() const [with T = void*]
bool Future<T>::get(T*, int) const [with T = void*]
I have tried to typedef Future<void*> without any luck.
If T is void* the const should be on the pointer not on the pointed memory:
void* const & (Future<void*>::*x)() const = &Future<void*>::get;
Templates themselves have no pointers. A template is a template, it tells c++ how to create a class. So
template<class T>
class Container {
public:
T* element() { return element_; }
void SetElement(Element *element) { element_ = element; }
typedef void (*SetElementFunctionPointer)(Element *element);
private:
T *element_;
};
typedef Container<int> IntContainer;
The code above shows you a Container template, and how you create an integer container (IntContainer) by using the Container template. In there I've declared a typedef for a SetElementFunctionPointer.
how do I provide extra member function for specialized template in a non-inline way?
i.e.
template<typename T>
class sets
{
void insert(const int& key, const T& val);
};
template<>
class sets<bool>
{
void insert(const int& key, const bool& val);
void insert(const int& key){ insert(key, true); };
};
But when I write sets<bool>::insert(const int& key) as
template<>
class sets<bool>
{
void insert(const int& key, const bool& val);
void insert(const int& key);
};
template<>
void sets<bool>::insert(const int& key)
{
insert(key, true);
}
GCC complains:
template-id ‘insert<>’ for ‘void
ip_set::insert(const int&)’ does
not match any template declaration
Besides what Effo said, if you want to add additional functionality in specializations you should move common functionality into a base template class. E.g.:
template<typename T>
class Base
{
public:
void insert(const int& key, const T& val)
{ map_.insert(std::make_pair(key, val)); }
private:
std::map<int, T> map_;
};
template<typename T>
class Wrapper : public Base<T> {};
template<>
class Wrapper<bool> : public Base<bool>
{
public:
using Base<bool>::insert;
void insert(const int& key);
};
void Wrapper<bool>::insert(const int& key)
{ insert(key, true); }
That's because it is not a function of your template so don't use "template<>". It works for me after removing "template<>" as below:
void sets<bool>::insert(const int& key)
{
insert(key, true);
}
My system FC9 x86_64.
The entire code:
template<typename T>
class sets
{
public:
void insert(const int& key, const T& val);
};
template<>
class sets<bool>
{
public:
void insert(const int& key, const bool& val) {}
void insert(const int& key);
};
void sets<bool>::insert(const int& key)
{
insert(key, true);
}
int main(int argc, char **argv)
{
sets<bool> ip_sets;
int key = 10;
ip_sets.insert(key);
return 0;
}
i think you should understand the following two points :
if the you want to specilize the class primary template, you must put the 'template<>' before the specilized edition declaration.but as for the member function, you needn't put the 'template<...>' before the member function definition(because the type info of the specilized template class has been set by you).
i don't think the primary template class has ant thing to do with the specilized edition.