Recursive Variadic Template Function - No ambiguity?
I am currently studying variadic templates, and as a small exercise to digest some of the stuff I had been reading about, I wrote a small function to output the names of all of its argument types:
#include "stdafx.h"
#include <iostream>
#include <string>
template<typename Next, typename... Rest>
std::string get_arg_types(Next next, Rest... rest)
{
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
}
template<typename Last>
std::string get_arg_types(Last last)
{
return std::string(typeid(Last).name());
}
int main()
{
float f = 0;
double d = 0;
int i = 0;
std::cout << get_arg_types(f, d, i);
return 0;
}
To my surprise, this compiled using VC++ 12.0 and (seems to) work just fine.
I expected an error due to ambiguity between the overload when there is only one argument remaining, because I read that a template parameter pack can be empty/contain 0 arguments.
So my question is why does this work? How is the "potential ambiguity" resolved? Are the signature for both functions not identical with only 1 arg? I feel like I may have missed some important concept somewhere, because in my head the above example shouldn't compile, but obviously I am wrong.
Kind regards :)
c++ templates variadic-templates variadic-functions
add a comment |
I am currently studying variadic templates, and as a small exercise to digest some of the stuff I had been reading about, I wrote a small function to output the names of all of its argument types:
#include "stdafx.h"
#include <iostream>
#include <string>
template<typename Next, typename... Rest>
std::string get_arg_types(Next next, Rest... rest)
{
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
}
template<typename Last>
std::string get_arg_types(Last last)
{
return std::string(typeid(Last).name());
}
int main()
{
float f = 0;
double d = 0;
int i = 0;
std::cout << get_arg_types(f, d, i);
return 0;
}
To my surprise, this compiled using VC++ 12.0 and (seems to) work just fine.
I expected an error due to ambiguity between the overload when there is only one argument remaining, because I read that a template parameter pack can be empty/contain 0 arguments.
So my question is why does this work? How is the "potential ambiguity" resolved? Are the signature for both functions not identical with only 1 arg? I feel like I may have missed some important concept somewhere, because in my head the above example shouldn't compile, but obviously I am wrong.
Kind regards :)
c++ templates variadic-templates variadic-functions
2
Possible duplicate of Ambiguous call when recursively calling variadic template function overload (Edit: the duplicate's question is slightly different but the answer does kinda cater to this...)
– TrebuchetMS
Nov 23 '18 at 11:29
@TrebuchetMS Thank you for the link, but I feel the answers for that question don't really tell me anything more than "in my example, there will be no ambiguity". I already know that. What I want to know is why (i.e. how is the potential ambiguity resolved)
– not an alien
Nov 23 '18 at 11:52
2
Concerning the possible duplicate link of TrebuchetMS: This is what Jarods answer explains (in the yellow box): if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack. Doesn't this answer why it works for the last?
– Scheff
Nov 23 '18 at 11:59
add a comment |
I am currently studying variadic templates, and as a small exercise to digest some of the stuff I had been reading about, I wrote a small function to output the names of all of its argument types:
#include "stdafx.h"
#include <iostream>
#include <string>
template<typename Next, typename... Rest>
std::string get_arg_types(Next next, Rest... rest)
{
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
}
template<typename Last>
std::string get_arg_types(Last last)
{
return std::string(typeid(Last).name());
}
int main()
{
float f = 0;
double d = 0;
int i = 0;
std::cout << get_arg_types(f, d, i);
return 0;
}
To my surprise, this compiled using VC++ 12.0 and (seems to) work just fine.
I expected an error due to ambiguity between the overload when there is only one argument remaining, because I read that a template parameter pack can be empty/contain 0 arguments.
So my question is why does this work? How is the "potential ambiguity" resolved? Are the signature for both functions not identical with only 1 arg? I feel like I may have missed some important concept somewhere, because in my head the above example shouldn't compile, but obviously I am wrong.
Kind regards :)
c++ templates variadic-templates variadic-functions
I am currently studying variadic templates, and as a small exercise to digest some of the stuff I had been reading about, I wrote a small function to output the names of all of its argument types:
#include "stdafx.h"
#include <iostream>
#include <string>
template<typename Next, typename... Rest>
std::string get_arg_types(Next next, Rest... rest)
{
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
}
template<typename Last>
std::string get_arg_types(Last last)
{
return std::string(typeid(Last).name());
}
int main()
{
float f = 0;
double d = 0;
int i = 0;
std::cout << get_arg_types(f, d, i);
return 0;
}
To my surprise, this compiled using VC++ 12.0 and (seems to) work just fine.
I expected an error due to ambiguity between the overload when there is only one argument remaining, because I read that a template parameter pack can be empty/contain 0 arguments.
So my question is why does this work? How is the "potential ambiguity" resolved? Are the signature for both functions not identical with only 1 arg? I feel like I may have missed some important concept somewhere, because in my head the above example shouldn't compile, but obviously I am wrong.
Kind regards :)
c++ templates variadic-templates variadic-functions
c++ templates variadic-templates variadic-functions
edited Nov 23 '18 at 11:55
not an alien
asked Nov 23 '18 at 11:26
not an aliennot an alien
317110
317110
2
Possible duplicate of Ambiguous call when recursively calling variadic template function overload (Edit: the duplicate's question is slightly different but the answer does kinda cater to this...)
– TrebuchetMS
Nov 23 '18 at 11:29
@TrebuchetMS Thank you for the link, but I feel the answers for that question don't really tell me anything more than "in my example, there will be no ambiguity". I already know that. What I want to know is why (i.e. how is the potential ambiguity resolved)
– not an alien
Nov 23 '18 at 11:52
2
Concerning the possible duplicate link of TrebuchetMS: This is what Jarods answer explains (in the yellow box): if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack. Doesn't this answer why it works for the last?
– Scheff
Nov 23 '18 at 11:59
add a comment |
2
Possible duplicate of Ambiguous call when recursively calling variadic template function overload (Edit: the duplicate's question is slightly different but the answer does kinda cater to this...)
– TrebuchetMS
Nov 23 '18 at 11:29
@TrebuchetMS Thank you for the link, but I feel the answers for that question don't really tell me anything more than "in my example, there will be no ambiguity". I already know that. What I want to know is why (i.e. how is the potential ambiguity resolved)
– not an alien
Nov 23 '18 at 11:52
2
Concerning the possible duplicate link of TrebuchetMS: This is what Jarods answer explains (in the yellow box): if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack. Doesn't this answer why it works for the last?
– Scheff
Nov 23 '18 at 11:59
2
2
Possible duplicate of Ambiguous call when recursively calling variadic template function overload (Edit: the duplicate's question is slightly different but the answer does kinda cater to this...)
– TrebuchetMS
Nov 23 '18 at 11:29
Possible duplicate of Ambiguous call when recursively calling variadic template function overload (Edit: the duplicate's question is slightly different but the answer does kinda cater to this...)
– TrebuchetMS
Nov 23 '18 at 11:29
@TrebuchetMS Thank you for the link, but I feel the answers for that question don't really tell me anything more than "in my example, there will be no ambiguity". I already know that. What I want to know is why (i.e. how is the potential ambiguity resolved)
– not an alien
Nov 23 '18 at 11:52
@TrebuchetMS Thank you for the link, but I feel the answers for that question don't really tell me anything more than "in my example, there will be no ambiguity". I already know that. What I want to know is why (i.e. how is the potential ambiguity resolved)
– not an alien
Nov 23 '18 at 11:52
2
2
Concerning the possible duplicate link of TrebuchetMS: This is what Jarods answer explains (in the yellow box): if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack. Doesn't this answer why it works for the last?
– Scheff
Nov 23 '18 at 11:59
Concerning the possible duplicate link of TrebuchetMS: This is what Jarods answer explains (in the yellow box): if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack. Doesn't this answer why it works for the last?
– Scheff
Nov 23 '18 at 11:59
add a comment |
1 Answer
1
active
oldest
votes
Your code is problematic, but for a different reason. As noted in a answer to the related question Ambiguous call when recursively calling variadic template function overload, the second overload in your code is considered more specialized. However, it should appear before the routine with the parameter pack. Compiling your code with gcc 8.2.1 or clang 6.0.1 gives an error like
variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67: recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67: required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39: required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()
As you can see from the error, even when get_arg_types has a single parameter, the compiler picks up the first overload, which in turns call get_arg_types without arguments. A simple solution is to move the overload of get_arg_types with a single parameter before the routine with the template parameter pack, or add a declaration of the single-parameter get_arg_types before the general routine.
Alternatively, you could eliminate your specialization single-parameter of get_arg_types and add a specialization with 0 parameters:
std::string get_arg_types()
{
return std::string();
}
Again, such a specialization should be put (or at least declared) before the template routine. Notice that with this second solution the output is slightly changed.
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%2f53445845%2frecursive-variadic-template-function-no-ambiguity%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
Your code is problematic, but for a different reason. As noted in a answer to the related question Ambiguous call when recursively calling variadic template function overload, the second overload in your code is considered more specialized. However, it should appear before the routine with the parameter pack. Compiling your code with gcc 8.2.1 or clang 6.0.1 gives an error like
variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67: recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67: required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39: required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()
As you can see from the error, even when get_arg_types has a single parameter, the compiler picks up the first overload, which in turns call get_arg_types without arguments. A simple solution is to move the overload of get_arg_types with a single parameter before the routine with the template parameter pack, or add a declaration of the single-parameter get_arg_types before the general routine.
Alternatively, you could eliminate your specialization single-parameter of get_arg_types and add a specialization with 0 parameters:
std::string get_arg_types()
{
return std::string();
}
Again, such a specialization should be put (or at least declared) before the template routine. Notice that with this second solution the output is slightly changed.
add a comment |
Your code is problematic, but for a different reason. As noted in a answer to the related question Ambiguous call when recursively calling variadic template function overload, the second overload in your code is considered more specialized. However, it should appear before the routine with the parameter pack. Compiling your code with gcc 8.2.1 or clang 6.0.1 gives an error like
variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67: recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67: required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39: required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()
As you can see from the error, even when get_arg_types has a single parameter, the compiler picks up the first overload, which in turns call get_arg_types without arguments. A simple solution is to move the overload of get_arg_types with a single parameter before the routine with the template parameter pack, or add a declaration of the single-parameter get_arg_types before the general routine.
Alternatively, you could eliminate your specialization single-parameter of get_arg_types and add a specialization with 0 parameters:
std::string get_arg_types()
{
return std::string();
}
Again, such a specialization should be put (or at least declared) before the template routine. Notice that with this second solution the output is slightly changed.
add a comment |
Your code is problematic, but for a different reason. As noted in a answer to the related question Ambiguous call when recursively calling variadic template function overload, the second overload in your code is considered more specialized. However, it should appear before the routine with the parameter pack. Compiling your code with gcc 8.2.1 or clang 6.0.1 gives an error like
variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67: recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67: required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39: required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()
As you can see from the error, even when get_arg_types has a single parameter, the compiler picks up the first overload, which in turns call get_arg_types without arguments. A simple solution is to move the overload of get_arg_types with a single parameter before the routine with the template parameter pack, or add a declaration of the single-parameter get_arg_types before the general routine.
Alternatively, you could eliminate your specialization single-parameter of get_arg_types and add a specialization with 0 parameters:
std::string get_arg_types()
{
return std::string();
}
Again, such a specialization should be put (or at least declared) before the template routine. Notice that with this second solution the output is slightly changed.
Your code is problematic, but for a different reason. As noted in a answer to the related question Ambiguous call when recursively calling variadic template function overload, the second overload in your code is considered more specialized. However, it should appear before the routine with the parameter pack. Compiling your code with gcc 8.2.1 or clang 6.0.1 gives an error like
variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67: recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67: required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39: required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
return std::string(typeid(Next).name()) + "n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()
As you can see from the error, even when get_arg_types has a single parameter, the compiler picks up the first overload, which in turns call get_arg_types without arguments. A simple solution is to move the overload of get_arg_types with a single parameter before the routine with the template parameter pack, or add a declaration of the single-parameter get_arg_types before the general routine.
Alternatively, you could eliminate your specialization single-parameter of get_arg_types and add a specialization with 0 parameters:
std::string get_arg_types()
{
return std::string();
}
Again, such a specialization should be put (or at least declared) before the template routine. Notice that with this second solution the output is slightly changed.
answered Nov 23 '18 at 13:00
francescofrancesco
8701212
8701212
add a comment |
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%2f53445845%2frecursive-variadic-template-function-no-ambiguity%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
Possible duplicate of Ambiguous call when recursively calling variadic template function overload (Edit: the duplicate's question is slightly different but the answer does kinda cater to this...)
– TrebuchetMS
Nov 23 '18 at 11:29
@TrebuchetMS Thank you for the link, but I feel the answers for that question don't really tell me anything more than "in my example, there will be no ambiguity". I already know that. What I want to know is why (i.e. how is the potential ambiguity resolved)
– not an alien
Nov 23 '18 at 11:52
2
Concerning the possible duplicate link of TrebuchetMS: This is what Jarods answer explains (in the yellow box): if one function template has a trailing parameter pack and the other does not, the one with the omitted parameter is considered to be more specialized than the one with the empty parameter pack. Doesn't this answer why it works for the last?
– Scheff
Nov 23 '18 at 11:59