Call non-specialised template class function from specialized template class function - c++

Is it possible to call a function defined in a non-specialised template class from a specialised template class? Here is an example of what i am attempting:
template <typename T>
struct Convert
{
static inline void toString(unsigned num, unsigned places, std::string& str) { ... }
};
template <>
struct Convert<int8_t>
{
static inline void toString(unsigned num, std::string& str)
{
Convert<int8_t>::toString(num, digitis(num), str);
}
};
GCC complains that it can't see the non-specialised class function; i.e. I guess it only looks within the specialised class.
Any thoughts?
EDIT
Here is a more concrete example from my code (with a possible solution):
struct NonSpecial { };
template <typename T>
class Convert
{
template <typename R>
static inline R fromString(const register char *str, const unsigned str_len)
{
R result = 0;
//convert str to R
return result;
}
friend class Convert<int8_t>;
friend class Convert<uint8_t>;
}
template <>
struct Convert<int8_t>
{
static inline int8_t fromString(const register char* str, const unsigned str_len = 4)
{
Convert<NonSpecial>::fromString<int8_t>(str, str_len);
}
};
template <>
struct Convert<uint8_t>
{
static inline uint8_t fromString(const register char* str, const unsigned str_len = 3)
{
Convert<NonSpecial>::fromString<uint8_t>(str, str_len);
}
};
I have other functions - toString(), countDigits(), etc. I have chosen this approach so I can keep the same function names for each type (i.e. don't need toStringU32(), toString32, etc.). I considered template specialization but I don't believe this is possible.

In general, this isn’t possible.
There are different possible solutions but they “cheat”. The first is to hoist off the actual default logic into a different function that is not specialized. Now you can call this function from both toString implementations.
The second alternative entails inheriting from the non-specialized class and passing a special tag as the template argument:
struct BaseClassTag { };
template <>
struct Convert<int8_t> : public Convert<BaseClassTag>
{
typedef Convert<BaseClassTag> TBase;
static inline void toString(unsigned num, std::string& str)
{
TBase::toString(num, digitis(num), str);
}
};

Related

Mapping type in cpp using template

I have a function template from an external library that needs user-defined type for using it.
template < int runtime_t >
typename ExtLib::apply<runtime_t>::type get_value(std::string) ;
To use it, I need to specify the user-defined type like:
get_value<ExtLib::pool_t::boolean_>("key_of_boolean_value");
get_value<ExtLib::pool_t::float_>("key_of_float_value");
I would like to wrap this "ExtLib" in order to hide it from the main program in such way I can use it with builtin cpp type:
bool val = get_value<bool>("key");
float val2 = get_value<float>("key2");
I've tried using a map but without any success. Is it even possible?
You could make mapping from standard types to lib types via class templates:
template <typename T>
struct Convert;
template <>
struct Convert<bool>
{
static const int value = ExtLib::pool_t::boolean;
};
template <>
struct Convert<float>
{
static const int value = ExtLib::pool_t::float;
};
.. map other types
and then
template <typename T>
auto get_value(const std::string& key)
{
return get_value<Convert<T>::value>(key)
}
Or you could define a function template get_value in your own namespace, and overload or specialize it to use the function with the same name from the library namespace, for ex.
// libadapter.h
namespace myns
{
template <typename T> T get_value(const string& key);
// specialize for bool, for ex.
template <bool>
bool get_value(const std::string& key)
{
return library::get_value<Extlib::pool_t::boolean>(key));
}
/* or
template <bool>
auto get_value(const std::string& key)
{
return static_cast<bool>(library::get_value<Extlib::pool_t::boolean>(key))
}
*/
// specialize for float
template <float>
float get_value(const std::string& key)
{
return library::get_value<Extlib::pool_t::float>(key);
}
// ... specialize for other types as well, if necccessary ...
}
then in some .cpp:
#include "libadapter.h"
using myns::get_value;
... use get_value ...
Thanks to #StPiere, I could answer my own question with:
std::undordered_map<std::type_index, int> map_types = {
{std::type_index(typeid(bool)), ExtLib::pool_t::boolean_},
{std::type_index(typeid(long)), ExtLib::pool_t::long_},
{std::type_index(typeid(float)), ExtLib::pool_t::float_},
{std::type_index(typeid(double)), ExtLib::pool_t::double_}
}
template <typename T>
T getValue(std::string key) {
const int TT = map_types[std::type_index(typeid(T))]
return get_value<TT>(key);
};

How to specialize a non-templated-member function of a template class for multiple types?

I'm biting of my nails on the syntax required to partially specialize a member function for multiple types. Here is what I have:
#include <cstdint>
#include <string>
class Property
{
public:
virtual int read(uint8_t *) = 0;
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *);
};
// specialized for std::string
template<>
int PropertyValue<std::string>::read(uint8_t *buf) { /* put string-value to buf */}
Now I would want to specialize the read-function for different enum-types. I tried a combination of enable_if and is_same which looks promissing, then putting it inside the template-declaration (compiler told me there are now 2 template arguments whereas 1 was expected).
Putting it inside the class-definition was not working either. Outside ... well, here's what I currently have.
// specialize for some enums
template<typename T>
typename std::enable_if<std::is_same<T, enum Enum1>::value ||
std::is_same<T, enum Enum2>::value, int>::type
PropertyValue<T>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
Where is my thinking wrong?
EDIT: Writing it like this compiles and works:
template<>
int PropertyValue<Enum 1>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
template<>
int PropertyValue<Enum 2>::read(uint8_t *buf)
{
return encode_enum(buf, value_);
}
PropertyValue::value itself is not a template. It's not a template class, it's not a template function. It's a member of a template class, which is not the same thing as being a template itself.
You have to specialize the entire class.
template<>
class PropertyValue<std::string>
{
std::string value_;
public:
int read(uint8_t *)
{
// Your specialization goes here.
}
};
Even if read() itself was a template, you must still specialize its class, before you can specialize a template class's template member.
Of course, if your template class has many other members and methods, every one of them have to be specialized here, leading to plenty of code getting duplicated. At that point, you will be faced with several options for refactoring out that duplicated code. The best approach for that depends on the particular details.
But that's how it's done...
EDIT: one common approach is to use a helper template class:
template<typename T> class PropertyValue; // Forward declaration
template<typename T> class do_read {
public:
static int do_it( PropertyValue<T> &me, uint8_t *p )
{
// your default implementation
}
};
template<> class do_read<std::string> {
public:
static int do_it( PropertyValue<std::string> &me, uint8_t *p )
{
// your specialization
}
};
template<typename T>
class PropertyValue
{
T value_;
public:
int read(uint8_t *p)
{
return do_read<T>::do_it(*this, p);
}
};

Method for two different types in template class C++

I want to do some kind of specialization, something like this:
template <typename Type, int Size>
class Example
{
//some values
public:
double length() const;
}
template <typename Type, int Size>
double Example<double, Size>::length() const {...}
template <typename Type, int Size>
double Example<MyType, Size>::length() const {...}
Obviously it doesn't work. How should I implement this method? I want Type to be explicitly declared and Size to be variable here.
One option is to specialize the class template for double and MyType.
template <typename Type, int Size>
class Example
{
public:
double length() const { /* Use a generic implementation */ }
}
// Specialize for double
template <int Size>
class Example<double, Size>
{
public:
double length() const { /* Use a double specific implementation */ }
}
// Specialize for MyType
template <int Size>
class Example<MyType, Size>
{
public:
double length() const { /* Use a MyType specific implementation */ }
}
The other option is to use another template class/function that can be used by the generic implementation of Example::length().
template <typename Type, int Size>
struct Length
{
// Generic implementation
static double get() { ... }
}
// Specialize Length for double and MyType
template <int Size>
struct Length<double, Size>
{
static double get() { ... }
}
template <int Size>
struct Length<MyType, Size>
{
static double get() { ... }
}
template <typename Type, int Size>
class Example
{
public:
double length() const { return Length<Type, Size>::get(); }
}
The second approach is better if everything else in Example but the length member function can be implemented using generic code.

What's the cheapest way to specialize a traits member

I have a traits class that is supposed to provide just one information about other types (in form of a string):
template<typename T>
struct some_traits {
static const char* const some_string;
};
I need to provide special instances of some_string for each type. The common way I know how to do this is to only declare some_traits, and then write specializations:
template<typename T>
struct some_traits;
template<>
struct some_traits<blah> {
static const char* const some_string;
};
const char* const some_traits<blah>::some_string = "blah string";
This is, however, a lot of code, when all I need is a specialized some_string. Is there a way to simplify this?
I have tried to fiddle with explicit specializations, but failed to come up with a syntax that doesn't make the compiler spit venomous error messages into my face.
Notes:
I know I can hide this behind a macro. I am still curious.
This needs to compile on an embedded platform with GCC 4.1. So C++03 is all we have. (Boost is fine, but for limited Posix support we're stuck with 1.52, in case this matters.)
It is possible to explicitly specialize members of class templates:
template<typename T>
struct some_traits {
static const char* const some_string;
};
template<>
char const* const some_traits<int>::some_string = "int";
This should reduce the overhead of declaring new specializations slightly. However, this technique cannot be applied to partial specializations:
template<typename T> struct foo {};
template<typename T>
char const* const some_traits<foo<T>>::some_string = "foo<T>"; // error
... that is, unless you add a partial specialization for some_traits:
template<typename T>
struct some_traits<foo<T>> {
char const* const some_string;
};
Two alternatives:
(1) Using ADL and functions
template<typename T> struct some_string_tag {};
template<typename T>
struct some_traits {
static const char* const some_string;
};
template<typename T>
char const* const some_traits<T>::some_string = get_string(some_string_tag<T>());
A specialization can then be written as:
char const* get_string(some_string_tag<int>) { return "int"; }
And partial specializations as:
template<typename T>
char const* get_string(some_string_tag<foo<T>>) { return "foo<T>"; }
(In this case, some_traits is a point for customizing how the string is found, and it provides convenient access to the string as a variable.)
(2) A second trait using an inline function
template<typename T>
char const* const some_traits<T>::some_string = some_traits_X<T>::get_string();
template<typename T> struct some_traits_X {
// provide: static char const* get_string();
};
template<>
struct some_traits_X<int> {
static char const* get_string() { return "int"; }
};
template<typename T>
struct some_traits_X<foo<T>> {
static char const* get_string() { return "foo<T>"; }
};
Why not use functions?
template<typename T>
struct some_traits {
static const char* const some_string();
};
template<>
struct some_traits<blah> {
static const char* const some_string() { return "blah string"; }
};

Default parameters for methods of template class

Is there a way to provide default parameter values for methods of a template class? For example I have the following:
template<class T>
class A
{
public:
A foo(T t);
};
How should I modify this to give foo a default parameter of type T? For example: T is int then a default value of -23, or T is char* then default value of "something", etc. Is this even possible?
If you want the default parameter to be just the default value (zero, usually), then you can write A foo(T t = T()). Otherwise, I suggest a trait class:
template <typename T> struct MyDefaults
{
static const T value = T();
};
template <> struct MyDefaults<int>
{
static const int value = -23;
};
template<class T>
class A
{
public:
A foo(T t = MyDefaults<T>::value);
};
Writing the constant value inside the class definition only works for integral types, I believe, so you may have to write it outside for all other types:
template <> struct MyDefaults<double>
{
static const double value;
};
const double MyDefaults<double>::value = -1.5;
template <> struct MyDefaults<const char *>
{
static const char * const value;
};
const char * const MyDefaults<const char *>::value = "Hello World";
In C++11, you could alternatively say static constexpr T value = T(); to make the template work for non-integral values, provided that T has a default constructor that is declared constexpr:
template <typename T> struct MyDefaults
{
static constexpr T value = T();
};
template <> struct MyDefaults<const char *>
{
static constexpr const char * value = "Hello World";
};