Yesterday I asked about template explicit specialization in class. Link.
Now I have the same purpose but now I wanna use inheritance to avoid code duplication. If I declare a function in the base class I cannot declare specialization of this function in the derived class.
My code:
#include <stdexcept>
#include <iostream>
class Base
{
public:
template <typename T>
T fun()
{
throw std::runtime_error("Unsupported template param");
}
};
class Derived : public Base
{
};
template <>
bool Base::fun<bool>()
{
return true;
}
template <>
float Derived::fun<float>()
{
return 5.6f;
}
template <>
double Derived::fun<double>()
{
return 5.684;
}
int main()
{
Derived d;
bool d_b = d.fun<bool>();
float d_f = d.fun<float>();
double d_d = d.fun<double>();
char d_error = d.fun<char>();
}
VS code errors:
use of inherited members is not allowed
g
error: template id "fun" for "float Derived :: fun ()" does not match any template declaration
Intel C compiler:
source/app.cpp:25:16: error: no function template matches function template specialization 'fun'
float Derived::fun<float>()
^
source/app.cpp:30:1: error: extraneous 'template<>' in declaration of variable 'fun'
template <>
^~~~~~~~~~~
source/app.cpp:31:17: error: redefinition of 'fun' as different kind of symbol
double Derived::fun<double>()
^
source/app.cpp:25:16: note: previous definition is here
float Derived::fun<float>()
If it is impossible in C , please answer another question: what is a wide-known practice in c to do what I want. Before I used D language and one man says me I don't ask a question "Why" to myself. And instead, I just try to transfer D methods to C . I agree. That's why I ask.
Maybe a better way is to ignore templates and declare separated functions? For example:
- funToBool()
- funToFloat()
- funToDouble()
CodePudding user response:
This will compile if you add a public template definition of fun in Derived.
But that will probably not do what you want.
In particular d.fun<bool>();
will not execute the implementation in Base, but the implementation in Derived.
You cannot specialize template functions in derived classes.
You also cannot use subtype polymorphism on template functions: template cannot be virtual.
You can achieve some type of static polymorphism using CRTP.
Yes removing templates and working with separated functions would work (a.toX()...).
Another option is to work with overloads (i.e. passing a dummy argument or the destination variable and write different implementations).
Adding an example for the dummy argument solution as requested:
namespace TO {
static const bool BOOL = false;
static const double DOUBLE = 0.0;
static const int INT = 0;
}
struct A {
bool convert(bool dummy) {
return true;
}
};
struct B : public A {
using A::convert; // important
int convert(int dummy) {
return 2;
}
double convert(double dummy) {
return 3.0;
}
};
int main() {
B b;
std::cout << b.convert(TO::BOOL) << std::endl;
std::cout << b.convert(TO::DOUBLE) << std::endl;
std::cout << b.convert(TO::INT) << std::endl;
}
With this kind of solution there is a risk of implicit conversion when calling the function. toX() might be a safer option.