How do I get around for not allowing templated virtual function
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
How do I work around for not having the support for templated virtual function?
I have a requirement to create a Builder/Command class which can store templated argument which is used later to call methods to do some processing.
Basically builder should be able to store templated values, maybe there is a different(more correct) way of doing it.
After setting all the values, later I want to call an execute method which will use the templated values to call an internal method.
class BuilderImpl {
public:
virtual void execute() = 0;
virtual int type() = 0;
private:
// common properties here
};
template <typename T1, typename T2>
class BuilderImpl2: public BuilderImpl {
public:
BuilderImpl2(const T1 &v1, const T2 &v2) : mVar1{v1}, mVar2{v2} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 2;
}
T1 mVar1;
T2 mVar2;
};
template <typename T>
class BuilderImpl1: public BuilderImpl {
public:
typedef BuilderImpl1<T> CLAZZ;
BuilderImpl1(const T &v) : mVar1{v} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 1;
}
template <typename T2>
std::shared_ptr<BuilderImpl> add(const T2 &v2) {
return std::make_shared<BuilderImpl2<T, T2>>(mVar1, v2);
}
T mVar1;
};
class Builder {
public:
void execute() {
std::cout << __FUNCTION__ << std::endl;
if (mImpl) {
mImpl->execute();
}
}
template <typename T>
void add(const T &v) {
if (!mImpl) {
mImpl = std::make_shared<BuilderImpl1<T>>(v);
} else if (mImpl->type() == 1) {
// How do I update my implementation mImpl to point with an instance of BuilderImpl2, any trick?
//mImpl = std::static_pointer_cast<BuilderImpl1<???>>(mImpl)->add(v);
}
}
protected:
std::shared_ptr<BuilderImpl> mImpl{ nullptr };
};
void templatebuilder() {
Builder builder;
builder.add(10);
builder.add(0.0);
builder.execute();
}
c++ c++11
add a comment |
How do I work around for not having the support for templated virtual function?
I have a requirement to create a Builder/Command class which can store templated argument which is used later to call methods to do some processing.
Basically builder should be able to store templated values, maybe there is a different(more correct) way of doing it.
After setting all the values, later I want to call an execute method which will use the templated values to call an internal method.
class BuilderImpl {
public:
virtual void execute() = 0;
virtual int type() = 0;
private:
// common properties here
};
template <typename T1, typename T2>
class BuilderImpl2: public BuilderImpl {
public:
BuilderImpl2(const T1 &v1, const T2 &v2) : mVar1{v1}, mVar2{v2} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 2;
}
T1 mVar1;
T2 mVar2;
};
template <typename T>
class BuilderImpl1: public BuilderImpl {
public:
typedef BuilderImpl1<T> CLAZZ;
BuilderImpl1(const T &v) : mVar1{v} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 1;
}
template <typename T2>
std::shared_ptr<BuilderImpl> add(const T2 &v2) {
return std::make_shared<BuilderImpl2<T, T2>>(mVar1, v2);
}
T mVar1;
};
class Builder {
public:
void execute() {
std::cout << __FUNCTION__ << std::endl;
if (mImpl) {
mImpl->execute();
}
}
template <typename T>
void add(const T &v) {
if (!mImpl) {
mImpl = std::make_shared<BuilderImpl1<T>>(v);
} else if (mImpl->type() == 1) {
// How do I update my implementation mImpl to point with an instance of BuilderImpl2, any trick?
//mImpl = std::static_pointer_cast<BuilderImpl1<???>>(mImpl)->add(v);
}
}
protected:
std::shared_ptr<BuilderImpl> mImpl{ nullptr };
};
void templatebuilder() {
Builder builder;
builder.add(10);
builder.add(0.0);
builder.execute();
}
c++ c++11
2
I am unable to correlate your description with your code. It's unclear to me what you are asking.
– R Sahu
Jan 4 at 3:14
I don't think this will work, since you don't have access to know whichT
was used to initializemImpl
whenadd()
is called a 2nd time with a differentT
. You may need to rethink your design to use fewer templated descendants and use more concrete classes for eachT
you want to support.
– Remy Lebeau
Jan 4 at 4:11
add a comment |
How do I work around for not having the support for templated virtual function?
I have a requirement to create a Builder/Command class which can store templated argument which is used later to call methods to do some processing.
Basically builder should be able to store templated values, maybe there is a different(more correct) way of doing it.
After setting all the values, later I want to call an execute method which will use the templated values to call an internal method.
class BuilderImpl {
public:
virtual void execute() = 0;
virtual int type() = 0;
private:
// common properties here
};
template <typename T1, typename T2>
class BuilderImpl2: public BuilderImpl {
public:
BuilderImpl2(const T1 &v1, const T2 &v2) : mVar1{v1}, mVar2{v2} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 2;
}
T1 mVar1;
T2 mVar2;
};
template <typename T>
class BuilderImpl1: public BuilderImpl {
public:
typedef BuilderImpl1<T> CLAZZ;
BuilderImpl1(const T &v) : mVar1{v} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 1;
}
template <typename T2>
std::shared_ptr<BuilderImpl> add(const T2 &v2) {
return std::make_shared<BuilderImpl2<T, T2>>(mVar1, v2);
}
T mVar1;
};
class Builder {
public:
void execute() {
std::cout << __FUNCTION__ << std::endl;
if (mImpl) {
mImpl->execute();
}
}
template <typename T>
void add(const T &v) {
if (!mImpl) {
mImpl = std::make_shared<BuilderImpl1<T>>(v);
} else if (mImpl->type() == 1) {
// How do I update my implementation mImpl to point with an instance of BuilderImpl2, any trick?
//mImpl = std::static_pointer_cast<BuilderImpl1<???>>(mImpl)->add(v);
}
}
protected:
std::shared_ptr<BuilderImpl> mImpl{ nullptr };
};
void templatebuilder() {
Builder builder;
builder.add(10);
builder.add(0.0);
builder.execute();
}
c++ c++11
How do I work around for not having the support for templated virtual function?
I have a requirement to create a Builder/Command class which can store templated argument which is used later to call methods to do some processing.
Basically builder should be able to store templated values, maybe there is a different(more correct) way of doing it.
After setting all the values, later I want to call an execute method which will use the templated values to call an internal method.
class BuilderImpl {
public:
virtual void execute() = 0;
virtual int type() = 0;
private:
// common properties here
};
template <typename T1, typename T2>
class BuilderImpl2: public BuilderImpl {
public:
BuilderImpl2(const T1 &v1, const T2 &v2) : mVar1{v1}, mVar2{v2} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 2;
}
T1 mVar1;
T2 mVar2;
};
template <typename T>
class BuilderImpl1: public BuilderImpl {
public:
typedef BuilderImpl1<T> CLAZZ;
BuilderImpl1(const T &v) : mVar1{v} {
}
virtual void execute() override {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual int type() override {
return 1;
}
template <typename T2>
std::shared_ptr<BuilderImpl> add(const T2 &v2) {
return std::make_shared<BuilderImpl2<T, T2>>(mVar1, v2);
}
T mVar1;
};
class Builder {
public:
void execute() {
std::cout << __FUNCTION__ << std::endl;
if (mImpl) {
mImpl->execute();
}
}
template <typename T>
void add(const T &v) {
if (!mImpl) {
mImpl = std::make_shared<BuilderImpl1<T>>(v);
} else if (mImpl->type() == 1) {
// How do I update my implementation mImpl to point with an instance of BuilderImpl2, any trick?
//mImpl = std::static_pointer_cast<BuilderImpl1<???>>(mImpl)->add(v);
}
}
protected:
std::shared_ptr<BuilderImpl> mImpl{ nullptr };
};
void templatebuilder() {
Builder builder;
builder.add(10);
builder.add(0.0);
builder.execute();
}
c++ c++11
c++ c++11
asked Jan 4 at 2:48
RanjithRanjith
206
206
2
I am unable to correlate your description with your code. It's unclear to me what you are asking.
– R Sahu
Jan 4 at 3:14
I don't think this will work, since you don't have access to know whichT
was used to initializemImpl
whenadd()
is called a 2nd time with a differentT
. You may need to rethink your design to use fewer templated descendants and use more concrete classes for eachT
you want to support.
– Remy Lebeau
Jan 4 at 4:11
add a comment |
2
I am unable to correlate your description with your code. It's unclear to me what you are asking.
– R Sahu
Jan 4 at 3:14
I don't think this will work, since you don't have access to know whichT
was used to initializemImpl
whenadd()
is called a 2nd time with a differentT
. You may need to rethink your design to use fewer templated descendants and use more concrete classes for eachT
you want to support.
– Remy Lebeau
Jan 4 at 4:11
2
2
I am unable to correlate your description with your code. It's unclear to me what you are asking.
– R Sahu
Jan 4 at 3:14
I am unable to correlate your description with your code. It's unclear to me what you are asking.
– R Sahu
Jan 4 at 3:14
I don't think this will work, since you don't have access to know which
T
was used to initialize mImpl
when add()
is called a 2nd time with a different T
. You may need to rethink your design to use fewer templated descendants and use more concrete classes for each T
you want to support.– Remy Lebeau
Jan 4 at 4:11
I don't think this will work, since you don't have access to know which
T
was used to initialize mImpl
when add()
is called a 2nd time with a different T
. You may need to rethink your design to use fewer templated descendants and use more concrete classes for each T
you want to support.– Remy Lebeau
Jan 4 at 4:11
add a comment |
2 Answers
2
active
oldest
votes
It’s impossible to do this in an automatic, extensible fashion: two translation units could define types A
and B
, necessitating the construction of an impossible type BuilderImpl2<A,B>
. (This is related to the fact that for n input types you need O(n^2) implementations.)
So you have to explicitly list the types you support for at least one side. The most direct way of doing this is with a ladder of dynamic_cast
s:
if(const auto p=dynamic_cast<BuilderImpl1<A>>(mImpl.get())) mImpl=p->add(v);
else if(const auto p=…) mImpl=p->add(v);
// …
else die_horribly();
(You might add a convenience method to let you write const auto p=mImpl->cast<A>()
.) There might be a nicer way of indexing with the dynamic type of the BuilderImpl1
, but that’s a separate issue.
add a comment |
This is a complement to Davis's answer.
The line typedef BuilderImpl1<T> CLAZZ;
let think that you are used to Java. There is a strong difference between Java and C++ here:
- Java uses generics with type erasure. There is only one class for any specialization, and simply controls are applied at compile time
- C++ use templates. There is one different class for every specialization, and that class must be defined at compile time. That is the reason why the implementation of templated classes must be in include files, unless you know all the implementations that will be used and declare them at compile time.
Complement to the complement: one usually uses the injected class name instead of such atypedef
.
– Davis Herring
Jan 4 at 15:32
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54032541%2fhow-do-i-get-around-for-not-allowing-templated-virtual-function%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
It’s impossible to do this in an automatic, extensible fashion: two translation units could define types A
and B
, necessitating the construction of an impossible type BuilderImpl2<A,B>
. (This is related to the fact that for n input types you need O(n^2) implementations.)
So you have to explicitly list the types you support for at least one side. The most direct way of doing this is with a ladder of dynamic_cast
s:
if(const auto p=dynamic_cast<BuilderImpl1<A>>(mImpl.get())) mImpl=p->add(v);
else if(const auto p=…) mImpl=p->add(v);
// …
else die_horribly();
(You might add a convenience method to let you write const auto p=mImpl->cast<A>()
.) There might be a nicer way of indexing with the dynamic type of the BuilderImpl1
, but that’s a separate issue.
add a comment |
It’s impossible to do this in an automatic, extensible fashion: two translation units could define types A
and B
, necessitating the construction of an impossible type BuilderImpl2<A,B>
. (This is related to the fact that for n input types you need O(n^2) implementations.)
So you have to explicitly list the types you support for at least one side. The most direct way of doing this is with a ladder of dynamic_cast
s:
if(const auto p=dynamic_cast<BuilderImpl1<A>>(mImpl.get())) mImpl=p->add(v);
else if(const auto p=…) mImpl=p->add(v);
// …
else die_horribly();
(You might add a convenience method to let you write const auto p=mImpl->cast<A>()
.) There might be a nicer way of indexing with the dynamic type of the BuilderImpl1
, but that’s a separate issue.
add a comment |
It’s impossible to do this in an automatic, extensible fashion: two translation units could define types A
and B
, necessitating the construction of an impossible type BuilderImpl2<A,B>
. (This is related to the fact that for n input types you need O(n^2) implementations.)
So you have to explicitly list the types you support for at least one side. The most direct way of doing this is with a ladder of dynamic_cast
s:
if(const auto p=dynamic_cast<BuilderImpl1<A>>(mImpl.get())) mImpl=p->add(v);
else if(const auto p=…) mImpl=p->add(v);
// …
else die_horribly();
(You might add a convenience method to let you write const auto p=mImpl->cast<A>()
.) There might be a nicer way of indexing with the dynamic type of the BuilderImpl1
, but that’s a separate issue.
It’s impossible to do this in an automatic, extensible fashion: two translation units could define types A
and B
, necessitating the construction of an impossible type BuilderImpl2<A,B>
. (This is related to the fact that for n input types you need O(n^2) implementations.)
So you have to explicitly list the types you support for at least one side. The most direct way of doing this is with a ladder of dynamic_cast
s:
if(const auto p=dynamic_cast<BuilderImpl1<A>>(mImpl.get())) mImpl=p->add(v);
else if(const auto p=…) mImpl=p->add(v);
// …
else die_horribly();
(You might add a convenience method to let you write const auto p=mImpl->cast<A>()
.) There might be a nicer way of indexing with the dynamic type of the BuilderImpl1
, but that’s a separate issue.
answered Jan 4 at 7:50
Davis HerringDavis Herring
9,0301736
9,0301736
add a comment |
add a comment |
This is a complement to Davis's answer.
The line typedef BuilderImpl1<T> CLAZZ;
let think that you are used to Java. There is a strong difference between Java and C++ here:
- Java uses generics with type erasure. There is only one class for any specialization, and simply controls are applied at compile time
- C++ use templates. There is one different class for every specialization, and that class must be defined at compile time. That is the reason why the implementation of templated classes must be in include files, unless you know all the implementations that will be used and declare them at compile time.
Complement to the complement: one usually uses the injected class name instead of such atypedef
.
– Davis Herring
Jan 4 at 15:32
add a comment |
This is a complement to Davis's answer.
The line typedef BuilderImpl1<T> CLAZZ;
let think that you are used to Java. There is a strong difference between Java and C++ here:
- Java uses generics with type erasure. There is only one class for any specialization, and simply controls are applied at compile time
- C++ use templates. There is one different class for every specialization, and that class must be defined at compile time. That is the reason why the implementation of templated classes must be in include files, unless you know all the implementations that will be used and declare them at compile time.
Complement to the complement: one usually uses the injected class name instead of such atypedef
.
– Davis Herring
Jan 4 at 15:32
add a comment |
This is a complement to Davis's answer.
The line typedef BuilderImpl1<T> CLAZZ;
let think that you are used to Java. There is a strong difference between Java and C++ here:
- Java uses generics with type erasure. There is only one class for any specialization, and simply controls are applied at compile time
- C++ use templates. There is one different class for every specialization, and that class must be defined at compile time. That is the reason why the implementation of templated classes must be in include files, unless you know all the implementations that will be used and declare them at compile time.
This is a complement to Davis's answer.
The line typedef BuilderImpl1<T> CLAZZ;
let think that you are used to Java. There is a strong difference between Java and C++ here:
- Java uses generics with type erasure. There is only one class for any specialization, and simply controls are applied at compile time
- C++ use templates. There is one different class for every specialization, and that class must be defined at compile time. That is the reason why the implementation of templated classes must be in include files, unless you know all the implementations that will be used and declare them at compile time.
answered Jan 4 at 8:51
Serge BallestaSerge Ballesta
81.4k961134
81.4k961134
Complement to the complement: one usually uses the injected class name instead of such atypedef
.
– Davis Herring
Jan 4 at 15:32
add a comment |
Complement to the complement: one usually uses the injected class name instead of such atypedef
.
– Davis Herring
Jan 4 at 15:32
Complement to the complement: one usually uses the injected class name instead of such a
typedef
.– Davis Herring
Jan 4 at 15:32
Complement to the complement: one usually uses the injected class name instead of such a
typedef
.– Davis Herring
Jan 4 at 15:32
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54032541%2fhow-do-i-get-around-for-not-allowing-templated-virtual-function%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
2
I am unable to correlate your description with your code. It's unclear to me what you are asking.
– R Sahu
Jan 4 at 3:14
I don't think this will work, since you don't have access to know which
T
was used to initializemImpl
whenadd()
is called a 2nd time with a differentT
. You may need to rethink your design to use fewer templated descendants and use more concrete classes for eachT
you want to support.– Remy Lebeau
Jan 4 at 4:11