Recursive Variadic Template Function - No ambiguity?












2















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 :)










share|improve this question




















  • 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















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 :)










share|improve this question




















  • 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








2








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 :)










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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
















  • 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














1 Answer
1






active

oldest

votes


















1














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.






share|improve this answer























    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
    });


    }
    });














    draft saved

    draft discarded


















    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









    1














    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.






    share|improve this answer




























      1














      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.






      share|improve this answer


























        1












        1








        1







        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.






        share|improve this answer













        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.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 23 '18 at 13:00









        francescofrancesco

        8701212




        8701212






























            draft saved

            draft discarded




















































            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.




            draft saved


            draft discarded














            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





















































            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







            Popular posts from this blog

            Feedback on college project

            Futebolista

            Albești (Vaslui)