Recursive Compound structure
I have a class that looks something like this:
template<class KeyType, class... Types>
class BasicCompound
{
public:
using mapped_type = std::variant
<
ValueWrapper<BasicCompound>
, ValueWrapper<Types>...
>;
using key_type = KeyType;
// Accessors for retreiving and modifying content
// ...
private:
std::map<key_type, mapped_type> m_content;
};
ValueWrapper
decides to put the content either inline or in a std::unique_ptr
. Would it be possible with a similar interface, possibly through some kind of proxy, to make the recursiveness optional? By optional I mean that the user should not automatically get the possibility to store the BasicCompound
inside itself, but rather specify it in the list of types.
What I have thought of:
- A
using
directive does not work. A new type cannot be defined in it self, and a predeclaration of a following typedef is not allowed. - Adding a
bool
to the list of types, and usestd::conditional_t
formapped_type
. However, if the user wants to store anX<BasicCompound>
, this approach fails. - Inject
mapped_type
from outside. Then I cannot hide the use of theValueWrapper
thing.
Using inheritance over a
typdef
like
struct MyCompound : BasicCompound<std::string, MyCompound, int> {};
This works but then the structure is not strictly recursive, as
MyCompound
now is a different type fromBasicCompound
. Maybe a CRTP-like approach could solve that problem, but then the inner compound type must be treated differently than the other types.
c++ recursive-datastructures
add a comment |
I have a class that looks something like this:
template<class KeyType, class... Types>
class BasicCompound
{
public:
using mapped_type = std::variant
<
ValueWrapper<BasicCompound>
, ValueWrapper<Types>...
>;
using key_type = KeyType;
// Accessors for retreiving and modifying content
// ...
private:
std::map<key_type, mapped_type> m_content;
};
ValueWrapper
decides to put the content either inline or in a std::unique_ptr
. Would it be possible with a similar interface, possibly through some kind of proxy, to make the recursiveness optional? By optional I mean that the user should not automatically get the possibility to store the BasicCompound
inside itself, but rather specify it in the list of types.
What I have thought of:
- A
using
directive does not work. A new type cannot be defined in it self, and a predeclaration of a following typedef is not allowed. - Adding a
bool
to the list of types, and usestd::conditional_t
formapped_type
. However, if the user wants to store anX<BasicCompound>
, this approach fails. - Inject
mapped_type
from outside. Then I cannot hide the use of theValueWrapper
thing.
Using inheritance over a
typdef
like
struct MyCompound : BasicCompound<std::string, MyCompound, int> {};
This works but then the structure is not strictly recursive, as
MyCompound
now is a different type fromBasicCompound
. Maybe a CRTP-like approach could solve that problem, but then the inner compound type must be treated differently than the other types.
c++ recursive-datastructures
add a comment |
I have a class that looks something like this:
template<class KeyType, class... Types>
class BasicCompound
{
public:
using mapped_type = std::variant
<
ValueWrapper<BasicCompound>
, ValueWrapper<Types>...
>;
using key_type = KeyType;
// Accessors for retreiving and modifying content
// ...
private:
std::map<key_type, mapped_type> m_content;
};
ValueWrapper
decides to put the content either inline or in a std::unique_ptr
. Would it be possible with a similar interface, possibly through some kind of proxy, to make the recursiveness optional? By optional I mean that the user should not automatically get the possibility to store the BasicCompound
inside itself, but rather specify it in the list of types.
What I have thought of:
- A
using
directive does not work. A new type cannot be defined in it self, and a predeclaration of a following typedef is not allowed. - Adding a
bool
to the list of types, and usestd::conditional_t
formapped_type
. However, if the user wants to store anX<BasicCompound>
, this approach fails. - Inject
mapped_type
from outside. Then I cannot hide the use of theValueWrapper
thing.
Using inheritance over a
typdef
like
struct MyCompound : BasicCompound<std::string, MyCompound, int> {};
This works but then the structure is not strictly recursive, as
MyCompound
now is a different type fromBasicCompound
. Maybe a CRTP-like approach could solve that problem, but then the inner compound type must be treated differently than the other types.
c++ recursive-datastructures
I have a class that looks something like this:
template<class KeyType, class... Types>
class BasicCompound
{
public:
using mapped_type = std::variant
<
ValueWrapper<BasicCompound>
, ValueWrapper<Types>...
>;
using key_type = KeyType;
// Accessors for retreiving and modifying content
// ...
private:
std::map<key_type, mapped_type> m_content;
};
ValueWrapper
decides to put the content either inline or in a std::unique_ptr
. Would it be possible with a similar interface, possibly through some kind of proxy, to make the recursiveness optional? By optional I mean that the user should not automatically get the possibility to store the BasicCompound
inside itself, but rather specify it in the list of types.
What I have thought of:
- A
using
directive does not work. A new type cannot be defined in it self, and a predeclaration of a following typedef is not allowed. - Adding a
bool
to the list of types, and usestd::conditional_t
formapped_type
. However, if the user wants to store anX<BasicCompound>
, this approach fails. - Inject
mapped_type
from outside. Then I cannot hide the use of theValueWrapper
thing.
Using inheritance over a
typdef
like
struct MyCompound : BasicCompound<std::string, MyCompound, int> {};
This works but then the structure is not strictly recursive, as
MyCompound
now is a different type fromBasicCompound
. Maybe a CRTP-like approach could solve that problem, but then the inner compound type must be treated differently than the other types.
c++ recursive-datastructures
c++ recursive-datastructures
edited Nov 22 '18 at 20:02
user877329
asked Nov 22 '18 at 19:47
user877329user877329
2,79632658
2,79632658
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
You can't have use a specialization of a class template as one of the template arguments of that specialization; there's no way to write it, and its name would be infinitely long. You can, however, use a wrapper to hold the recursive type:
template<class> class MaybeRecursive;
template<class T>
struct Wrapper {
using type=T;
};
struct MRWrapper {
using type=MaybeRecursive<MRWrapper>;
};
template<class T>
struct MaybeRecursive {
using type=typename T::type;
type *child;
};
void f() {
int x;
MaybeRecursive<Wrapper<int>> nonrec={&x};
MRWrapper::type rec={&rec};
}
MRWrapper
can be made a class template to provide additional template arguments to MaybeRecursive
.
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
@user877329: You can't writeX<X<...>,Y>
where the...
makes the template argument equivalent to the outer type. Nor can you writeX<A,Y>
whereA
is an alias forX<A,Y>
. This is (implementation guidance for) the closest you can get.
– Davis Herring
Nov 23 '18 at 17:18
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%2f53437279%2frecursive-compound-structure%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can't have use a specialization of a class template as one of the template arguments of that specialization; there's no way to write it, and its name would be infinitely long. You can, however, use a wrapper to hold the recursive type:
template<class> class MaybeRecursive;
template<class T>
struct Wrapper {
using type=T;
};
struct MRWrapper {
using type=MaybeRecursive<MRWrapper>;
};
template<class T>
struct MaybeRecursive {
using type=typename T::type;
type *child;
};
void f() {
int x;
MaybeRecursive<Wrapper<int>> nonrec={&x};
MRWrapper::type rec={&rec};
}
MRWrapper
can be made a class template to provide additional template arguments to MaybeRecursive
.
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
@user877329: You can't writeX<X<...>,Y>
where the...
makes the template argument equivalent to the outer type. Nor can you writeX<A,Y>
whereA
is an alias forX<A,Y>
. This is (implementation guidance for) the closest you can get.
– Davis Herring
Nov 23 '18 at 17:18
add a comment |
You can't have use a specialization of a class template as one of the template arguments of that specialization; there's no way to write it, and its name would be infinitely long. You can, however, use a wrapper to hold the recursive type:
template<class> class MaybeRecursive;
template<class T>
struct Wrapper {
using type=T;
};
struct MRWrapper {
using type=MaybeRecursive<MRWrapper>;
};
template<class T>
struct MaybeRecursive {
using type=typename T::type;
type *child;
};
void f() {
int x;
MaybeRecursive<Wrapper<int>> nonrec={&x};
MRWrapper::type rec={&rec};
}
MRWrapper
can be made a class template to provide additional template arguments to MaybeRecursive
.
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
@user877329: You can't writeX<X<...>,Y>
where the...
makes the template argument equivalent to the outer type. Nor can you writeX<A,Y>
whereA
is an alias forX<A,Y>
. This is (implementation guidance for) the closest you can get.
– Davis Herring
Nov 23 '18 at 17:18
add a comment |
You can't have use a specialization of a class template as one of the template arguments of that specialization; there's no way to write it, and its name would be infinitely long. You can, however, use a wrapper to hold the recursive type:
template<class> class MaybeRecursive;
template<class T>
struct Wrapper {
using type=T;
};
struct MRWrapper {
using type=MaybeRecursive<MRWrapper>;
};
template<class T>
struct MaybeRecursive {
using type=typename T::type;
type *child;
};
void f() {
int x;
MaybeRecursive<Wrapper<int>> nonrec={&x};
MRWrapper::type rec={&rec};
}
MRWrapper
can be made a class template to provide additional template arguments to MaybeRecursive
.
You can't have use a specialization of a class template as one of the template arguments of that specialization; there's no way to write it, and its name would be infinitely long. You can, however, use a wrapper to hold the recursive type:
template<class> class MaybeRecursive;
template<class T>
struct Wrapper {
using type=T;
};
struct MRWrapper {
using type=MaybeRecursive<MRWrapper>;
};
template<class T>
struct MaybeRecursive {
using type=typename T::type;
type *child;
};
void f() {
int x;
MaybeRecursive<Wrapper<int>> nonrec={&x};
MRWrapper::type rec={&rec};
}
MRWrapper
can be made a class template to provide additional template arguments to MaybeRecursive
.
answered Nov 22 '18 at 21:10
Davis HerringDavis Herring
8,4801736
8,4801736
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
@user877329: You can't writeX<X<...>,Y>
where the...
makes the template argument equivalent to the outer type. Nor can you writeX<A,Y>
whereA
is an alias forX<A,Y>
. This is (implementation guidance for) the closest you can get.
– Davis Herring
Nov 23 '18 at 17:18
add a comment |
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
@user877329: You can't writeX<X<...>,Y>
where the...
makes the template argument equivalent to the outer type. Nor can you writeX<A,Y>
whereA
is an alias forX<A,Y>
. This is (implementation guidance for) the closest you can get.
– Davis Herring
Nov 23 '18 at 17:18
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
I guess that this is very similar to my option (3) in terms of usage: I cannot use the content directly, but must go through the wrapper type.
– user877329
Nov 23 '18 at 17:04
@user877329: You can't write
X<X<...>,Y>
where the ...
makes the template argument equivalent to the outer type. Nor can you write X<A,Y>
where A
is an alias for X<A,Y>
. This is (implementation guidance for) the closest you can get.– Davis Herring
Nov 23 '18 at 17:18
@user877329: You can't write
X<X<...>,Y>
where the ...
makes the template argument equivalent to the outer type. Nor can you write X<A,Y>
where A
is an alias for X<A,Y>
. This is (implementation guidance for) the closest you can get.– Davis Herring
Nov 23 '18 at 17:18
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%2f53437279%2frecursive-compound-structure%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