Date: Sat, 27 Apr 2019 06:46:42 -0700
Yes I agree with the statement that offsets of the virtual functions needs to known at the call sites. But I am not sure I understand what you mean by “class type is complete”. If you mean after the definition of the concrete type Child then this has some problems with multiple child classes – do all concrete derived classes specify their list of explicit instantiations, I would think not.
In my understanding, the explicit instantiations must be declared right after the class definition which declares/defines the templatized virtual function and is the first one in the inheritance chain (Base) to do so. Please let me know if this doesn’t make sense.
Thanks,
Ritwik
Sent from Mail for Windows 10
From: Andrew Tomazos
Sent: Wednesday, April 24, 2019 11:10 PM
To: Ritwik Das
Cc: std-discussion_at_[hidden]; Jack Adrian Zappa
Subject: Re: [std-discussion] Templatized virtual functions
No, the vtable needs to be available when the class type is complete (at the end of the class definition). When the compiler is compiling a call to a virtual function, it hardcodes the offset in the vtable of the function at the call site. It therefore needs to know what these offsets are.
It would be conceivable to invent a syntax where the only possible instantiations of a member function template are listed after the declaration in the class definition. It could then create a vtable with exactly that many entries for it. It's not clear if this would be a good or useful feature though. You would need to analyze it thoughally in a proposal.
On Thu, Apr 25, 2019 at 2:17 AM Ritwik Das <ritwik.sami1990_at_[hidden]> wrote:
So why would explicit instantiation of function templates work in this case:
class Base
{
template<typename T>
virtual int func() = 0;
};
template int Base::func<int>();
template int Base::func<float>();
Shouldn't this tell the compiler exactly how many entries in the vtable to create and for which exact types instead of relying on the usages? Is it an ordering problem with other compilation units?
On Sun, Apr 21, 2019 at 3:10 PM Andrew Tomazos <andrewtomazos_at_[hidden]> wrote:
The virtual function table (vtable) is compiled into every translation unit (.o file) where the polymorphic type appears and then one is picked (at random) by the linker when the program is formed. Therefore, they have to be all the same. If vtables were built as needed then they would be different in each translation unit, and the linking algorithm wouldn't work.
On Mon, Apr 22, 2019 at 4:57 AM Ritwik Das via Std-Discussion <std-discussion_at_[hidden]> wrote:
Can’t this problem be worked around with template declarations within the same compilation unit which tells the compiler which templates to instantiate?
Sent from Mail for Windows 10
From: Jack Adrian Zappa
Sent: Saturday, April 20, 2019 5:37 PM
To: std-discussion_at_[hidden]
Cc: Ritwik Das
Subject: Re: [std-discussion] Templatized virtual functions
The reason that this doesn't work is because templated functions are not instantiated (compiled into binary code) until they are used. The vtable needs an actual address to point to, and is generated at the time that the class is. As a templated function could have any type, it would be impossible for a vtable to be generated that would be big enough to accept any type. Well, maybe it could, but it would be impractical.
A possible way around this is to accept a proxy:
#include <assert.h>
class unexpected_type : std::exception {
char const* what() override { return "Unexpected type passed"; }
};
enum types
{
int_e, float_e
};
class Base
{
virtual int func(types) = 0;
};
class Child
{
int func_int() { return 1; }
int func_float() { return 0; };
int funct(types type) {
switch(type) {
case int_e: return func_int();
case float_e: return func_float();
default:
assert(false);
throw unexpected_type();
}
};
void main()
{
Base* p = new Child();
int i = p->func(int_e);
int j = p->func(float_e);
delete p;
}
Note that this is just one way. Another possible method would be to use a class proxy that can have a virtual function to be able to tell the programme what to do next. The virtual function would then accept the base class. You might want to lookup type erasure c++.
HTH
A
Virus-free. www.avg.com
On Sat, Apr 20, 2019 at 3:17 PM Ritwik Das via Std-Discussion <std-discussion_at_[hidden]> wrote:
Hello,
I am almost sure this has come up before so I am looking for reasons why this will not work or why this proposal has not been accepted by the standard committee.
The following proposal does not change the way virtual functions work but only helps in writing them in a more easier and concise manner by allowing composability with template args.
Current approach:
class Base
{
virtual int func_int() = 0;
virtual int func_float() = 0;
};
class Child
{
virtual int func_int() { return 1; }
virtual int func_float() { return 0; };
};
void main()
{
Base* p = new Child();
int i = p->func_int();
int j = p->func_float();
delete p;
}
Proposal:
class Base
{
template<typename T>
virtual int func() = 0;
};
class Child
{
template<typename T>
virtual int func()
{
if (std::is_same_v<T, int>) return 0;
return 1;
}
};
void main()
{
Base* p = new Child();
int i = p->func<int>(); // Internally the compiler can create named functions like func_int()
int j = p->func<float>();
delete p;
}
In my understanding, the explicit instantiations must be declared right after the class definition which declares/defines the templatized virtual function and is the first one in the inheritance chain (Base) to do so. Please let me know if this doesn’t make sense.
Thanks,
Ritwik
Sent from Mail for Windows 10
From: Andrew Tomazos
Sent: Wednesday, April 24, 2019 11:10 PM
To: Ritwik Das
Cc: std-discussion_at_[hidden]; Jack Adrian Zappa
Subject: Re: [std-discussion] Templatized virtual functions
No, the vtable needs to be available when the class type is complete (at the end of the class definition). When the compiler is compiling a call to a virtual function, it hardcodes the offset in the vtable of the function at the call site. It therefore needs to know what these offsets are.
It would be conceivable to invent a syntax where the only possible instantiations of a member function template are listed after the declaration in the class definition. It could then create a vtable with exactly that many entries for it. It's not clear if this would be a good or useful feature though. You would need to analyze it thoughally in a proposal.
On Thu, Apr 25, 2019 at 2:17 AM Ritwik Das <ritwik.sami1990_at_[hidden]> wrote:
So why would explicit instantiation of function templates work in this case:
class Base
{
template<typename T>
virtual int func() = 0;
};
template int Base::func<int>();
template int Base::func<float>();
Shouldn't this tell the compiler exactly how many entries in the vtable to create and for which exact types instead of relying on the usages? Is it an ordering problem with other compilation units?
On Sun, Apr 21, 2019 at 3:10 PM Andrew Tomazos <andrewtomazos_at_[hidden]> wrote:
The virtual function table (vtable) is compiled into every translation unit (.o file) where the polymorphic type appears and then one is picked (at random) by the linker when the program is formed. Therefore, they have to be all the same. If vtables were built as needed then they would be different in each translation unit, and the linking algorithm wouldn't work.
On Mon, Apr 22, 2019 at 4:57 AM Ritwik Das via Std-Discussion <std-discussion_at_[hidden]> wrote:
Can’t this problem be worked around with template declarations within the same compilation unit which tells the compiler which templates to instantiate?
Sent from Mail for Windows 10
From: Jack Adrian Zappa
Sent: Saturday, April 20, 2019 5:37 PM
To: std-discussion_at_[hidden]
Cc: Ritwik Das
Subject: Re: [std-discussion] Templatized virtual functions
The reason that this doesn't work is because templated functions are not instantiated (compiled into binary code) until they are used. The vtable needs an actual address to point to, and is generated at the time that the class is. As a templated function could have any type, it would be impossible for a vtable to be generated that would be big enough to accept any type. Well, maybe it could, but it would be impractical.
A possible way around this is to accept a proxy:
#include <assert.h>
class unexpected_type : std::exception {
char const* what() override { return "Unexpected type passed"; }
};
enum types
{
int_e, float_e
};
class Base
{
virtual int func(types) = 0;
};
class Child
{
int func_int() { return 1; }
int func_float() { return 0; };
int funct(types type) {
switch(type) {
case int_e: return func_int();
case float_e: return func_float();
default:
assert(false);
throw unexpected_type();
}
};
void main()
{
Base* p = new Child();
int i = p->func(int_e);
int j = p->func(float_e);
delete p;
}
Note that this is just one way. Another possible method would be to use a class proxy that can have a virtual function to be able to tell the programme what to do next. The virtual function would then accept the base class. You might want to lookup type erasure c++.
HTH
A
Virus-free. www.avg.com
On Sat, Apr 20, 2019 at 3:17 PM Ritwik Das via Std-Discussion <std-discussion_at_[hidden]> wrote:
Hello,
I am almost sure this has come up before so I am looking for reasons why this will not work or why this proposal has not been accepted by the standard committee.
The following proposal does not change the way virtual functions work but only helps in writing them in a more easier and concise manner by allowing composability with template args.
Current approach:
class Base
{
virtual int func_int() = 0;
virtual int func_float() = 0;
};
class Child
{
virtual int func_int() { return 1; }
virtual int func_float() { return 0; };
};
void main()
{
Base* p = new Child();
int i = p->func_int();
int j = p->func_float();
delete p;
}
Proposal:
class Base
{
template<typename T>
virtual int func() = 0;
};
class Child
{
template<typename T>
virtual int func()
{
if (std::is_same_v<T, int>) return 0;
return 1;
}
};
void main()
{
Base* p = new Child();
int i = p->func<int>(); // Internally the compiler can create named functions like func_int()
int j = p->func<float>();
delete p;
}
-- Ritwik Das -- Std-Discussion mailing list Std-Discussion_at_[hidden] http://lists.isocpp.org/mailman/listinfo.cgi/std-discussion -- Std-Discussion mailing list Std-Discussion_at_[hidden] http://lists.isocpp.org/mailman/listinfo.cgi/std-discussion -- Ritwik Das
Received on 2019-04-27 08:48:23