Template explicit specialization in class using inheritance - c++

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()

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.

Related

How to access the member of a template parameter's? "Member access to incomplete type"

I'm trying to declare a class "Lambdas" that would provide lambdas (and their type information) to another class "Test". Lambdas also is holding the "this" reference to concrete Test instance for access of Test public members, inside the lambdas.
I do it to define the lambdas once and then to deduce types anywhere else through decltype()
But I get error: Member access to incomplete type:
template <typename T>
struct LambdasInstances {
T * self;
explicit LambdasInstances(T * p) : self(p) {} // CAPTURE Test "this"
auto genLambda1() {
return [=](int x){
self->testVar; // ERROR: Member access to incomplete type
};
}
};
class Test3 {
public:
LambdasInstances<Test3> instances;
int testVar;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
void useLambda() { varLambda(123); }
};
BUT IF I would make genLambda() externally defined, then I would run to another problem - ERROR: genLambda() with deduced type cannot be used before its defined!:
template <typename T>
struct LambdasInstances {
T * self;
explicit LambdasInstances(T * p) : self(p) {}
auto genLambda1(); // would be defined after Test3 declaration
};
class Test3 {
public:
int testVar;
LambdasInstances<Test3> instances;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
};
// IF WE DEFINE AFTER :: ^ genLambda() with deduced type cannot be used before its defined!
template< typename T>
auto LambdasInstances<T>::genLambda1() {
return [=](int x){
self->testVar;
};
}
The compiler might require the definition of the whole type available to be able to know the offset of the members (e.g. in the expression self->testVar, the compiler has to know the offset of testVar), but it might not be able to know the offset of a particular member until it will get the whole definition, because the compiler must know the alignment of your structure/class (I would even guess that some not straight forward logic might be involved when computing the padding between members) that comes after the knowledge of all members, see this, that is totally compiler and platform specific.
So back to your problem. You tell the compiler to define Test3 with genLambda1 as a member, that is a lambda that has to know the offset of member testVar. Seems easy, right? But the offset of testVar depends on the definition of the whole Test3 (see the paragraph above) - here we are in the loop.
You would say: "Hey stupid compiler, I give only a pointer to the lambda, not a copy by value where you have to know the whole size of the `Test3, why would you stop me from doing that?". Quite a legit question because theoretically compiler can resolve offset later, but seems like the compilers are not smart enough. And the standard says:
The lambda-expression’s compound-statement yields the function-body (8.4) of the function call operator ...
That basically says that the lambda body is the function body, but in the function body you cannot have incomplete types right? Lambdas are relatively new to C++ and not all corner cases are elaborated, so let's hope that in some future this will be resolved, of course the compilers will be more complicated as well as the standard.
For you problem I see the following resolution:
template <typename T>
struct LambdasInstances {
explicit LambdasInstances(T* p) : _lambda([=](int x) { return p->testVar; }) {}
auto genLambda1() { return _lambda; }
private:
std::function<void(int)> _lambda;
};
class Test3 {
public:
int testVar;
LambdasInstances<Test3> instances;
Test3() : instances(this) {}
decltype(instances.genLambda1()) varLambda = instances.genLambda1();
};
int main() {
Test3 test3;
Test3* test3_ptr;
LambdasInstances<Test3> instances(&test3);
auto lambda = [=](int x) { return test3_ptr->testVar; };
std::function<void(int)> functor = lambda;
cerr << sizeof(Test3) << endl;
cerr << sizeof(LambdasInstances<Test3>) << endl;
cerr << sizeof(lambda) << endl;
cerr << sizeof(functor) << endl;
return 0;
}
The difference is that std::function gives you a level of abstraction that protects the type LambdasInstances::genLambda1 from the definition of Test3. Unfortunately, as you will see from the main output the function takes more memory than the lambda. If this does not satisfy your needs I recommend to revise the design and may be you will find something in the old good techniques before the era of lambdas.

Alternative to overloading functions with derived types

Sorry for the uninformative title, I don't really know what to call what I am asking.
I want to achieve the following: Having a container of a base class type with instances of derived types, accessing the containers and calling a function overload dependent on the type of the derived object accessed. In a question earlier I asked here I learned that the static design I had in mind so far, does not work. The way I tried is this:
struct Int2TypeBase{
};
template <int v>
struct Int2Type : public Int2TypeBase
{
enum
{
value = v
};
};
void f(const Int2Type<0>&){
std::cout << "f(const Int2Type<0>&)" << "\n";
}
void f(const Int2Type<1>&){
std::cout << "f(const Int2Type<1>&)" << "\n";
}
int main(){
using namespace std;
std::vector<std::reference_wrapper<Int2TypeBase>> v;
Int2Type<0> i2t_1;
v.emplace_back(i2t_1);
Int2Type<1> i2t_2;
v.emplace_back(i2t_2);
auto x0 = v[0];
auto x1 = v[1];
f(x0.get()); // After my imagination this would have called void f(const Int2Type<0>&)
f(x1.get()); // After my imagination this would have called void f(const Int2Type<1>&)
}
Ok, so I want the correct overload of f to be selected, this however does not compile as at compile time it is unknown which type x0 and x1 actually have. But is there some alternate design that can realize this behavior?
Overloading is a static mechanism based on static types.
If you want to change behaviour dynamically based on the dynamic type of an object, C++ provides another built-in language feature for that: Virtual functions. Use them like this:
struct Int2TypeBase
{
virtual void do_f() = 0;
};
template <int v> struct Int2Type : Int2TypeBase
{
void do_f() override
{
// specific behaviour for Int2Type<v> goes here
}
/* ... */
};
void f(Int2TypeBase & x) { x.do_f(); }
Now you can call f on any base subobject and the correct behaviour is selected at runtime. In particular, f(x0.get()) and f(x1.get()) now select and dispatch to Int2Type<0>::do_f and Int2Type<1>::do_f at runtime, respectively.

Template inheritance: There are no arguments that depend on a template parameter [duplicate]

This question already has an answer here:
g++ template parameter error
(1 answer)
Closed 6 years ago.
I came across this error when compiling the following code.
After doing some research and reading similar errors in different situations, I came up with the solution I needed.
But I did not fully understood the undelying reason for the error and the fix.
template <typename T>
class TestA {
int a;
T temp;
protected:
int b;
public:
int c;
TestA(T te): a{10}, b{20}, c{30}, temp{te} {}
int geta(){ return a; }
int getb(){ return b; }
int getc(){ return c; }
};
template <typename T>
class TestB {
int atb;
T tempb;
protected:
int btb;
public:
int ctb;
TestB(T te) atb{10}, btb{20}, ctb{30}, tempb{te} {}
};
template <typename T>
class TestInh : public TestA<T>, public TestB<T> {
int aa;
T temptemp;
protected:
int bb;
int b;
public:
int cc;
TestInh(T te) : TestA<T>{te}, TestB<T>{te}, bb{10000}, b{-1000} {}
int get_total() {
// The error happens here!
return geta();
}
};
int main(int argc, char const *argv[]) {
char text = 'a';
TestInh<char> test(text);
//std::cout << test.geta() << std::endl;
std::cout << test.get_total() << std::endl;
//std::cout << test.c << std::endl;
return 0;
}
When compiling this code, I got this error:
testtemplate.cc: In member function ‘int TestInh<T>::get_total()’:
testtemplate.cc:54:32: error: there are no arguments to ‘geta’ that depend on a template parameter, so a declaration of ‘geta’ must be available [-fpermissive]
int get_total() {return geta();}
^
testtemplate.cc:54:32: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
It is solved by calling this->geta() instead of just geta(), but I do not fully understand why this cannot be resolved by the compiler.
Can someone please explain me why?
When extending a class that depends on a template parameter, this kind of become a dependent name.
The problem is that while performing two phase name lookup, the compiler can't know where he can find the function geta. He cannot know it comes from the parent. Because template specialization is a thing, TestA<int> and TestA<double> could be two completely different clas swith different functions and members.
With the this keyword added, the compiler know that geta must be a member function.
Without that, it could be either a member function or non-member function, or a member function of TestB.
Imagine a template code that will either call a function geta from TestA and geta from TestB depending on some template conditions. Ouch. The compiler want to be sure that the code is consistent for every template instantiations.
Another way of saying to the compiler that the function exist as a member function is to add a using statement:
template <typename T>
struct TestInh : TestA<T>, TestB<T> {
// some code...
using TestA<T>::geta;
int get_total() {
// works! With the above using statement,
// the compiler knows that 'geta()' is
// a member function of TestA<T>!
return geta();
}
};

C++ adding friend to a template class in order to typecast

I'm currently reading "Effective C++" and there is a chapter that contains code similiar to this:
template <typename T>
class Num {
public:
Num(int n) { ... }
};
template <typename T>
Num<T> operator*(const Num<T>& lhs, const Num<T>& rhs) { ... }
Num<int> n = 5 * Num<int>(10);
The book says that this won't work (and indeed it doesn't) because you can't expect the compiler to use implicit typecasting to specialize a template.
As a soluting it is suggested to use the "friend" syntax to define the function inside the class.
//It works
template <typename T>
class Num {
public:
Num(int n) { ... }
friend
Num operator*(const Num& lhs, const Num& rhs) { ... }
};
Num<int> n = 5 * Num<int>(10);
And the book suggests to use this friend-declaration thing whenever I need implicit conversion to a template class type. And it all seems to make sense.
But why can't I get the same example working with a common function, not an operator?
template <typename T>
class Num {
public:
Num(int n) { ... }
friend
void doFoo(const Num& lhs) { ... }
};
doFoo(5);
This time the compiler complaints that he can't find any 'doFoo' at all.
And if i declare the doFoo outside the class, i get the reasonable mismatched types error. Seems like the "friend ..." part is just being ignored.
So is there a problem with my understanding? What is the difference between a function and an operator in this case?
The reason is that here
doFoo(5);
the compiler has no way of finding foo, given an int parameter. This would be the equivalent of calling your friend operator like this:
Num<int> n = 5 * 10;
This will "work", but not by calling the friend operator* defined in your Num class, but by calling the built-in operator* for integers, and then using the implicit conversion from Num's converting constructor.
The core problem is lookup. A friend declaration provides a declaration of a namespace level function, but the declaration is only available inside the class that is befriending it. In the example the book provides that is not an issue: the function takes two arguments of the enclosing type, as long as one of them is of the enclosing type, Argument Dependent Lookup will look inside the definition of the class and find the operator. In your case that is not the case, since there is a single argument and that needs a conversion, the compiler will not look inside the definition of the class.
Note that this is regardless of templates and conversions:
class A {
friend void f( int ) {}
friend void g( int, A ) {}
};
int main() {
f(5); // Error: lookup cannot find 'f' declared *only* inside A
g(5,A()); // Ok, one argument is 'A', lookup will find the function
}
In the case above, where there are no templates involved, you could potentially add a declaration at namespace level to fix it, but that is not really an option for template classes.
class A {
friend void f() { std::cout << "inside A\n"; }
};
void f(int); // only declaration
int main() {
f(5); // "inside A"
}
This cannot be done for a template (and for all instantiating types) as the friend declaration is a declaration of a non-templated function. Although you could can play with the code just for the sake of testing:
template <typename T>
struct Num {
Num(int x) ...
friend void f( Num const & );
};
Num<int> f(Num<int> const &); // only declaration
int main() {
f(5);
}
Yes these code compiler do not know how to work with it .
like
doFoo(5)
compiler do not know 5 is int

How do I call a friend template function defined inside a class?

I got this example from my book, but I have no idea how to actually call the ticket function. This is the code:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
I get the "candidate function(s) not accessible" error message.
A few points will help you figure out what's going on here:
I) Friend function definitions within classes can only be found by Argument dependent lookup when called from outside the class definition.
II) Function templates that are supplied explicit template arguments do not undergo ADL unless the compiler is given some explicit help in identifying the call as a function call.
III) Argument dependent lookup (ADL) only works for user defined types.
A few examples will better illustrate each of the above points:
//------------------------
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
};
S s;
int i = f(3); // error - ADL does not work for ints, (III)
int j = f(s); // ok - ADL works for UDTs and helps find friend function - calls 2 (III)
// so how do we call function 1? If the compiler won't find the name via ADL
// declare the function in the namespace scope (since that is where the friend function
// gets injected)
int f(int); // This function declaration refers to the same function as #1
int k = f(3); // ok - but not because of ADL
// ok now lets add some friend templates and make this interesting
struct S
{
friend int f(int) { return 0; } // 1
friend int f(S) { return 0; } // 2
template<class T> friend int g(int) { return 0; } // 3
template<class T> friend int g(S) { return 0; } // 4
template<class T> friend int g() { return 0; } // 5
};
S s;
int k = g(5); // error - no ADL (III)
int l = g(s); // ok - ADL - calls 4
int m = g<int>(s); // should call 4 - but no ADL (point II above)
// ok so point II above says we have to give the compiler some help here
// We have to tell the compiler that g<int> identifies a function
// The way to do that is to add a visible dummy template function declaration
template<class /*Dummy*/, class /*TriggerADL*/> void g();
int m = g<int>(s); // ok - compiler recognizes fun call, ADL triggered - calls 4
int n = g<int>(3); // still not ok - no ADL for ints
// so how do we call either function 3 or 5 since we cannot rely on ADL?
// Remember friend functions are injected into the outer namespace
// so lets just declare the functions in the outer namespace (as we did above)
// both these declarations of g below refer to their counterparts defined in S
template<class T> int g(int);
template<class T> int g();
int o = g<int>(3); // ok
int p = g<int>(); // ok
// Of course once you have these two declarations at namespace scope
// you can get rid of the Dummy, TriggerADL declaration.
Ok so now lets return to the Vandevoorde example that you quoted, and now this should be easy:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter;
template<class T> int ticket(); // <-- this should work with a conformant compiler
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Hope that helps :)
Hotfix
There is a hot-fix available, but read the below explanation if you want to understand what's going on.
#include <iostream>
template<typename T> int ticket();
class Manager {
public:
template<typename T>
friend int ticket() {
return ++Manager::counter;
}
static int counter;
};
int Manager::counter; // don't forget the definition
int main() {
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
As the snippet shows, you have to declare the template to make it visible when you call it.
Friend function definitions
This is confusing, since there are some rules in the way in this case. Some basic points, and then some other points.
struct A {
friend void f(A*) { std::cout << "hello"; }
};
What does it do? It defines a friend function. Such a function is a member of the enclosing namespace. It's not a class member, even though it is defined within a class! The fact that it's defined within a class only changes the lexical scope of that function: It can refer to that class' members directly, without preceding the class-name.
Most importantly, though, the function is not visible after being declared. You cannot take its address doing something like this, for example
&f
The only way that the function would work is using argument dependent lookup. A lookup that ends up having that class as its associated class will consider that friend function. That means that the following works:
f((A*)0);
It works because the call includes an argument with type that has the class included. In that case, the class is an associated class, and the friend declaration will be considered.
The following won't work, for example
f(0);
Because it has no idea that it should look within A to find a friend declaration. A friend function definition of a function without an argument won't be found, because there is no argument dependent lookup happening, then.
Friend function definition for templates
In addition to the fact that your call does not include arguments, it has another problem. If you define a friend function template, the matter is more complicated. There is a rule that says that if the compiler sees T<A1, A2, A3>, that this only refers to a template specialization if T actually resolves to a template. Consider
ticket < int > ()
The compiler can't resolve ticket, because it is not visible to normal lookup. Therefor, the rule says that ticket<int> does not refer to a function. It has to be parsed as a relational expression, yielding to the following
(ticket < int) > ()
That will be a syntax error, because int is not a value, and () is neither a value.
Example
Here is an example where it matters.
struct A {
template<int I> friend void f(A*) { }
};
// try to comment this out
template<typename Dummy> void f();
int main() {
f<1>((A*)0);
}
That compiles. It compiles because f resolves to a template (although a completely different one that can't even accept a non-type template argument - but that doesn't matter!). But a Standard conforming compiler will not compile the snippet once you comment out the second declaration, because it's compiled as a relational expression (less-than and smaller-than) and it will not find symbol f.
Read this thread for further information: What am I missing in this template toy example?.
I do get the same error using the MS VS++ compiler. According to the docs on MSDN:
http://msdn.microsoft.com/en-us/library/h2x4fzdz(VS.80).aspx
Friends are not in the class's scope,
and they are not called using the
member-selection operators (. and –>)
unless they are members of another
class. A friend function is declared
by the class that is granting access.
So friend functions are not actually part of the class and should therefore not be defined in class scope. Define the function outside of the class:
#include <iostream>
class Manager {
public:
template<typename T>
friend int ticket();
static int counter;
};
template<typename T>
int ticket() {
return ++Manager::counter;
}
int Manager::counter;
int main()
{
Manager m;
std::cout << "ticket: " << ticket<int>() << std::endl;
}
Why not make it static instead?
#include <iostream>
class Manager {
public:
template<typename T>
static int ticket()
{
return ++Manager::counter;
}
static int counter;
};
int main()
{
Manager m;
std::cout << "ticket: " << Manager::ticket<int>() << std::endl;
}
Though really, it doesn't have to be a template either. I assume you needed information specifically about friend templates?