C++ list of unspecialized template type objects?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I've looked for questions on this subject, and although there are similar ones, none really address my question. So, here I go.
Suppose I have a template type F, and I declare a series of specializations as member variables of another object:
F<A> a;
F<B> b;
.
.
.
Later, I'd like to iterate over these and perform an operation that is defined on any F instance.
So my impulse is to create a std::list< F> but this does not work.
Is there a way to create a list of objects of type F, that is, without specifying the template parameter?
My hunch is no, not in C++, but hoping I am wrong.
c++ templates
add a comment |
I've looked for questions on this subject, and although there are similar ones, none really address my question. So, here I go.
Suppose I have a template type F, and I declare a series of specializations as member variables of another object:
F<A> a;
F<B> b;
.
.
.
Later, I'd like to iterate over these and perform an operation that is defined on any F instance.
So my impulse is to create a std::list< F> but this does not work.
Is there a way to create a list of objects of type F, that is, without specifying the template parameter?
My hunch is no, not in C++, but hoping I am wrong.
c++ templates
What you mean is an instantiation, not a specialization.
– SergeyA
Nov 13 '18 at 20:16
What I see is what inheritance does. You want to create a list with the parent class type, and have several children types into the list. I am not familiar how to do it with templates but inheritances is he first thing that came to my mind with your description
– fernando.reyes
Nov 13 '18 at 20:18
add a comment |
I've looked for questions on this subject, and although there are similar ones, none really address my question. So, here I go.
Suppose I have a template type F, and I declare a series of specializations as member variables of another object:
F<A> a;
F<B> b;
.
.
.
Later, I'd like to iterate over these and perform an operation that is defined on any F instance.
So my impulse is to create a std::list< F> but this does not work.
Is there a way to create a list of objects of type F, that is, without specifying the template parameter?
My hunch is no, not in C++, but hoping I am wrong.
c++ templates
I've looked for questions on this subject, and although there are similar ones, none really address my question. So, here I go.
Suppose I have a template type F, and I declare a series of specializations as member variables of another object:
F<A> a;
F<B> b;
.
.
.
Later, I'd like to iterate over these and perform an operation that is defined on any F instance.
So my impulse is to create a std::list< F> but this does not work.
Is there a way to create a list of objects of type F, that is, without specifying the template parameter?
My hunch is no, not in C++, but hoping I am wrong.
c++ templates
c++ templates
edited Nov 13 '18 at 20:16
nzc
asked Nov 13 '18 at 20:15
nzcnzc
401517
401517
What you mean is an instantiation, not a specialization.
– SergeyA
Nov 13 '18 at 20:16
What I see is what inheritance does. You want to create a list with the parent class type, and have several children types into the list. I am not familiar how to do it with templates but inheritances is he first thing that came to my mind with your description
– fernando.reyes
Nov 13 '18 at 20:18
add a comment |
What you mean is an instantiation, not a specialization.
– SergeyA
Nov 13 '18 at 20:16
What I see is what inheritance does. You want to create a list with the parent class type, and have several children types into the list. I am not familiar how to do it with templates but inheritances is he first thing that came to my mind with your description
– fernando.reyes
Nov 13 '18 at 20:18
What you mean is an instantiation, not a specialization.
– SergeyA
Nov 13 '18 at 20:16
What you mean is an instantiation, not a specialization.
– SergeyA
Nov 13 '18 at 20:16
What I see is what inheritance does. You want to create a list with the parent class type, and have several children types into the list. I am not familiar how to do it with templates but inheritances is he first thing that came to my mind with your description
– fernando.reyes
Nov 13 '18 at 20:18
What I see is what inheritance does. You want to create a list with the parent class type, and have several children types into the list. I am not familiar how to do it with templates but inheritances is he first thing that came to my mind with your description
– fernando.reyes
Nov 13 '18 at 20:18
add a comment |
3 Answers
3
active
oldest
votes
Unless all F<X>
derive from some common base-class independent of X
, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo
, then of course you can iterate over them as as Foo&
/Foo*
, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant
or std::any
.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>
s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fs
foo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo
X mem;
public:
explicit Foo(X arg) : mem(arg)
void foo()
std::cout << mem;
;
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X>
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
;
template <class X, class ...Ys>
class Holder : public Holder<Ys...>
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
Holder<Ys...>::call();
;
int main()
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
add a comment |
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
add a comment |
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int>
and a std::vector<char>
are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base
virtual void print() = 0;
;
template <typename T>
struct foo : foo_base
foo(T data) : data(data)
virtual void print() override
std::cout << data << std::endl;
private: T data;
;
void example()
foo<int> f(42);
f.print();
Here, a foo<int>
and a foo<char>
are separate types (as distinct instantiations of the foo<>
template), but all foo<>
instantiations derive from foo_base
. (Unless, of course, you provide an explicit specialization of foo<>
which does not derive from foo_base
...)
You do not need to providevirtual
for virtual overrides, this is just syntax noise.
– SergeyA
Nov 13 '18 at 20:37
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
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%2f53288822%2fc-list-of-unspecialized-template-type-objects%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
Unless all F<X>
derive from some common base-class independent of X
, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo
, then of course you can iterate over them as as Foo&
/Foo*
, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant
or std::any
.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>
s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fs
foo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo
X mem;
public:
explicit Foo(X arg) : mem(arg)
void foo()
std::cout << mem;
;
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X>
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
;
template <class X, class ...Ys>
class Holder : public Holder<Ys...>
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
Holder<Ys...>::call();
;
int main()
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
add a comment |
Unless all F<X>
derive from some common base-class independent of X
, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo
, then of course you can iterate over them as as Foo&
/Foo*
, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant
or std::any
.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>
s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fs
foo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo
X mem;
public:
explicit Foo(X arg) : mem(arg)
void foo()
std::cout << mem;
;
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X>
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
;
template <class X, class ...Ys>
class Holder : public Holder<Ys...>
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
Holder<Ys...>::call();
;
int main()
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
add a comment |
Unless all F<X>
derive from some common base-class independent of X
, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo
, then of course you can iterate over them as as Foo&
/Foo*
, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant
or std::any
.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>
s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fs
foo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo
X mem;
public:
explicit Foo(X arg) : mem(arg)
void foo()
std::cout << mem;
;
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X>
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
;
template <class X, class ...Ys>
class Holder : public Holder<Ys...>
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
Holder<Ys...>::call();
;
int main()
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
Unless all F<X>
derive from some common base-class independent of X
, this is only be possible using type erasure or heterogeneous containers.
If they all inherit from Foo
, then of course you can iterate over them as as Foo&
/Foo*
, but I guess you knew that.
If they have different types the standard-containers cannot hold them, because they are homogeneous - all elements have the same type. There is probably some library with heterogeneous containers, but in the STL, you can only emulate this with std::variant
or std::any
.
The last way I could imagine this works out - I don't recommend this - is by creating the enclosing class as a derived class of the F<X>
s (variadic template) and encoding the invocations into the hierarchy, s.t. every Fs
foo` is called
Since this is somewhat more involved here is a sample:
#include <iostream>
template <class X>
class Foo
X mem;
public:
explicit Foo(X arg) : mem(arg)
void foo()
std::cout << mem;
;
template <class X, class ...Xs> class Holder;
template <class X>
class Holder<X>
X member;
public:
Holder(X arg) : member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
;
template <class X, class ...Ys>
class Holder : public Holder<Ys...>
X member;
public:
Holder(X arg, Ys ...args) : Holder<Ys...>(std::forward<decltype(args)>(args)...), member(std::forward<decltype(arg)>(arg))
void call()
member.foo();
Holder<Ys...>::call();
;
int main()
// omitting the template-args requires c++17 deduction guides
Holder holder(Foo(4), Foo(" Hello "), Foo(7L), Foo(" World "));
holder.call();
std::cout << std::endl;
You maybe able to guess, that this is typically not what you want, because it is super-complex. I actually omitted some things like perfectly forwarding the arguments to keep it somewhat minimal, s.t. one can hopefully understand the concept.
edited Nov 13 '18 at 23:19
answered Nov 13 '18 at 21:16
midormidor
3,81611343
3,81611343
add a comment |
add a comment |
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
add a comment |
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
add a comment |
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
Unfortunately, the answer is NO. In C++ you can't have a container of heterogeneous unrelated objects, and different instantiations of the same template are unrelated.
The only way to make it work is to use some form of the type erasure. The most idiomatic is to use inheritance and virtual functions, and put pointers to base object into your list.
answered Nov 13 '18 at 20:19
SergeyASergeyA
44.7k53990
44.7k53990
add a comment |
add a comment |
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int>
and a std::vector<char>
are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base
virtual void print() = 0;
;
template <typename T>
struct foo : foo_base
foo(T data) : data(data)
virtual void print() override
std::cout << data << std::endl;
private: T data;
;
void example()
foo<int> f(42);
f.print();
Here, a foo<int>
and a foo<char>
are separate types (as distinct instantiations of the foo<>
template), but all foo<>
instantiations derive from foo_base
. (Unless, of course, you provide an explicit specialization of foo<>
which does not derive from foo_base
...)
You do not need to providevirtual
for virtual overrides, this is just syntax noise.
– SergeyA
Nov 13 '18 at 20:37
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
add a comment |
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int>
and a std::vector<char>
are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base
virtual void print() = 0;
;
template <typename T>
struct foo : foo_base
foo(T data) : data(data)
virtual void print() override
std::cout << data << std::endl;
private: T data;
;
void example()
foo<int> f(42);
f.print();
Here, a foo<int>
and a foo<char>
are separate types (as distinct instantiations of the foo<>
template), but all foo<>
instantiations derive from foo_base
. (Unless, of course, you provide an explicit specialization of foo<>
which does not derive from foo_base
...)
You do not need to providevirtual
for virtual overrides, this is just syntax noise.
– SergeyA
Nov 13 '18 at 20:37
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
add a comment |
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int>
and a std::vector<char>
are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base
virtual void print() = 0;
;
template <typename T>
struct foo : foo_base
foo(T data) : data(data)
virtual void print() override
std::cout << data << std::endl;
private: T data;
;
void example()
foo<int> f(42);
f.print();
Here, a foo<int>
and a foo<char>
are separate types (as distinct instantiations of the foo<>
template), but all foo<>
instantiations derive from foo_base
. (Unless, of course, you provide an explicit specialization of foo<>
which does not derive from foo_base
...)
As far as C++ is concerned, two different template instantiations of a template class or struct are completely separate types and have no relation to each other whatsoever. For example, a std::vector<int>
and a std::vector<char>
are separate types; neither derives from the other or from any common base. The fact that both types arose from instantiations of the same template does not create a semantic relationship between the types. In that sense (and that sense only) you might think of templates like preprocessor macros which are expanded before compilation to declare new and unrelated types.
But, you can create such a relationship yourself using inheritance, just as you would with any non-template types:
#include <iostream>
struct foo_base
virtual void print() = 0;
;
template <typename T>
struct foo : foo_base
foo(T data) : data(data)
virtual void print() override
std::cout << data << std::endl;
private: T data;
;
void example()
foo<int> f(42);
f.print();
Here, a foo<int>
and a foo<char>
are separate types (as distinct instantiations of the foo<>
template), but all foo<>
instantiations derive from foo_base
. (Unless, of course, you provide an explicit specialization of foo<>
which does not derive from foo_base
...)
edited Nov 13 '18 at 20:30
answered Nov 13 '18 at 20:24
TypeIATypeIA
13.9k2543
13.9k2543
You do not need to providevirtual
for virtual overrides, this is just syntax noise.
– SergeyA
Nov 13 '18 at 20:37
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
add a comment |
You do not need to providevirtual
for virtual overrides, this is just syntax noise.
– SergeyA
Nov 13 '18 at 20:37
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
You do not need to provide
virtual
for virtual overrides, this is just syntax noise.– SergeyA
Nov 13 '18 at 20:37
You do not need to provide
virtual
for virtual overrides, this is just syntax noise.– SergeyA
Nov 13 '18 at 20:37
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
@SergeyA That's true, but perhaps a bit pedantic, and certainly not related to OP's question.
– TypeIA
Nov 13 '18 at 20:40
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%2f53288822%2fc-list-of-unspecialized-template-type-objects%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
What you mean is an instantiation, not a specialization.
– SergeyA
Nov 13 '18 at 20:16
What I see is what inheritance does. You want to create a list with the parent class type, and have several children types into the list. I am not familiar how to do it with templates but inheritances is he first thing that came to my mind with your description
– fernando.reyes
Nov 13 '18 at 20:18