Why can't the template parameters of this function be inferred for this nested templated struct?










0















I have this nested templated struct:



template <typename... Ts>
struct A

template <unsigned i>
struct B

int b;
;
;


That compiles fine.



Then I try to define this function.



template <unsigned i, typename... Ts>
void foo(A<Ts...>::B<i> var)

std::cout << var.b << std::endl;



For some reason I don't completely understand, that won't compile. I had to change it in the following way for it to work.



template <unsigned i, typename... Ts>
void foo(typename A<Ts...>::template B<i> var)

std::cout << var.b << std::endl;



But then, when I call it like so:



A<int, float>::B<0> var = 0;
foo(var);


It says that template parameter i cannot be deducted.



I can make it work by adding the template arguments explicitly to the function call:



A<int, float>::B<0> var = 0;
foo<0, int, float>(var);


Why is that? How can I make it so I don't have to specify the template parameters in the function call?



Try the code: https://repl.it/repls/LavenderDefiantOctagons










share|improve this question




























    0















    I have this nested templated struct:



    template <typename... Ts>
    struct A

    template <unsigned i>
    struct B

    int b;
    ;
    ;


    That compiles fine.



    Then I try to define this function.



    template <unsigned i, typename... Ts>
    void foo(A<Ts...>::B<i> var)

    std::cout << var.b << std::endl;



    For some reason I don't completely understand, that won't compile. I had to change it in the following way for it to work.



    template <unsigned i, typename... Ts>
    void foo(typename A<Ts...>::template B<i> var)

    std::cout << var.b << std::endl;



    But then, when I call it like so:



    A<int, float>::B<0> var = 0;
    foo(var);


    It says that template parameter i cannot be deducted.



    I can make it work by adding the template arguments explicitly to the function call:



    A<int, float>::B<0> var = 0;
    foo<0, int, float>(var);


    Why is that? How can I make it so I don't have to specify the template parameters in the function call?



    Try the code: https://repl.it/repls/LavenderDefiantOctagons










    share|improve this question


























      0












      0








      0








      I have this nested templated struct:



      template <typename... Ts>
      struct A

      template <unsigned i>
      struct B

      int b;
      ;
      ;


      That compiles fine.



      Then I try to define this function.



      template <unsigned i, typename... Ts>
      void foo(A<Ts...>::B<i> var)

      std::cout << var.b << std::endl;



      For some reason I don't completely understand, that won't compile. I had to change it in the following way for it to work.



      template <unsigned i, typename... Ts>
      void foo(typename A<Ts...>::template B<i> var)

      std::cout << var.b << std::endl;



      But then, when I call it like so:



      A<int, float>::B<0> var = 0;
      foo(var);


      It says that template parameter i cannot be deducted.



      I can make it work by adding the template arguments explicitly to the function call:



      A<int, float>::B<0> var = 0;
      foo<0, int, float>(var);


      Why is that? How can I make it so I don't have to specify the template parameters in the function call?



      Try the code: https://repl.it/repls/LavenderDefiantOctagons










      share|improve this question
















      I have this nested templated struct:



      template <typename... Ts>
      struct A

      template <unsigned i>
      struct B

      int b;
      ;
      ;


      That compiles fine.



      Then I try to define this function.



      template <unsigned i, typename... Ts>
      void foo(A<Ts...>::B<i> var)

      std::cout << var.b << std::endl;



      For some reason I don't completely understand, that won't compile. I had to change it in the following way for it to work.



      template <unsigned i, typename... Ts>
      void foo(typename A<Ts...>::template B<i> var)

      std::cout << var.b << std::endl;



      But then, when I call it like so:



      A<int, float>::B<0> var = 0;
      foo(var);


      It says that template parameter i cannot be deducted.



      I can make it work by adding the template arguments explicitly to the function call:



      A<int, float>::B<0> var = 0;
      foo<0, int, float>(var);


      Why is that? How can I make it so I don't have to specify the template parameters in the function call?



      Try the code: https://repl.it/repls/LavenderDefiantOctagons







      c++ templates






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 12 '18 at 21:45







      tuket

















      asked Nov 12 '18 at 21:38









      tukettuket

      6771824




      6771824






















          3 Answers
          3






          active

          oldest

          votes


















          4














          Because the standard says so.



          The standard says so because inverting arbitrary compile time maps is equivalent to Halt.



          It is equivalent to Halt because template metaprogramming is Turing complete.



          It is Turing complete because it is actually hard to make a useful programming language that isn't Turing complete; it happens by accident, and avoiding it leads to a language that requires annoying workaround for seemingly simple things.



          So the problem in general, of determining which A the A<int, float>::B<0> is from and reversing that mapping, is hard, so the C++ standard says the compiler doesn't try.



          If you write your own mapping you can do it. First, you have to realize that B types have no "hair" in that there is nothing about the type of B that attaches it back to the type of A used to create it. We can add "hair":



          template<class...Ts>
          struct A
          template<unsigned i>
          struct B
          using daddy = A;
          int b;
          ;
          ;


          now we can find A from the type of B<?>.



          Next let's add some inverse maps:



           template<class...Ts>
          struct types_t using type=types_t;;

          template<class X>
          struct get_types;
          template<class X>
          using get_types_t=typename get_types<X>::type;
          template<template<class...>class Z, class...Ts>
          struct get_types<Z<Ts...>>:types_t<Ts...>;
          template<class B>
          struct get_B_index;
          template<unsigned i, template<unsigned>class B>
          struct get_B_index<B<i>>:std::integral_constant<unsigned, i>;


          and from this we can get A's template arguments from B:



           template<class...Ts, unsigned i>
          void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var )

          template<class B>
          void foo( B b )
          using types = get_types_t< typename B::daddy >;
          using index = get_B_index< B >;
          return foo( types, index, b );



          Live example






          share|improve this answer























          • Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

            – tuket
            Nov 12 '18 at 22:15











          • "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

            – AnT
            Nov 12 '18 at 22:52












          • @tuket yes, I am. It is known as Halt.

            – Yakk - Adam Nevraumont
            Nov 13 '18 at 0:03











          • @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

            – Yakk - Adam Nevraumont
            Nov 13 '18 at 0:06


















          2














          Template argument deduction can't deduce anything that appears in a nested-name-specifier. For example, it won't allow T to be deduced from a parameter of type typename Foo<T>::bar. I believe that the reason for this is that such deduction is not possible in general; there can always be partial specializations of Foo that define bar to be some arbitrarily complicated typedef.



          The workaround is to define the nested type as an unnested type then bring it in using a typedef, but use the original unnested name for deduction:



          template <unsigned i, typename... Ts>
          struct A_B int b;

          template <typename... Ts>
          struct A
          template <unsigned i> using B = A_B<i, Ts...>;
          ;

          template <unsigned i, typename... Ts>
          void foo(A_B<i, Ts...> var);





          share|improve this answer


















          • 1





            It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

            – SergeyA
            Nov 12 '18 at 21:58











          • Thanks, I like this solution because it's simple

            – tuket
            Nov 12 '18 at 22:17


















          0














          In your specific case the nested type B is uniquely attached to the specific specialization of the enclosing type A. There's one-to-one correspondence between various Bs and their enclosing As. So, theoretically it should be possible to deduce the arguments of A from a specific B.



          However, in general case the nested type name might refer to an alias (e.g. typedef-name), as opposed to a genuinely new type name (as in your example). In case of nested alias the 1:1 correspondence no longer holds, which is demonstrated by the examples in other answers.



          The language specification does not distinguish between these two situations (a genuinely new nested type vs. a nested alias), so it opts for the "common denominator" approach and just always treats the enclosing template parameters as non-deduced context.






          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%2f53270480%2fwhy-cant-the-template-parameters-of-this-function-be-inferred-for-this-nested-t%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









            4














            Because the standard says so.



            The standard says so because inverting arbitrary compile time maps is equivalent to Halt.



            It is equivalent to Halt because template metaprogramming is Turing complete.



            It is Turing complete because it is actually hard to make a useful programming language that isn't Turing complete; it happens by accident, and avoiding it leads to a language that requires annoying workaround for seemingly simple things.



            So the problem in general, of determining which A the A<int, float>::B<0> is from and reversing that mapping, is hard, so the C++ standard says the compiler doesn't try.



            If you write your own mapping you can do it. First, you have to realize that B types have no "hair" in that there is nothing about the type of B that attaches it back to the type of A used to create it. We can add "hair":



            template<class...Ts>
            struct A
            template<unsigned i>
            struct B
            using daddy = A;
            int b;
            ;
            ;


            now we can find A from the type of B<?>.



            Next let's add some inverse maps:



             template<class...Ts>
            struct types_t using type=types_t;;

            template<class X>
            struct get_types;
            template<class X>
            using get_types_t=typename get_types<X>::type;
            template<template<class...>class Z, class...Ts>
            struct get_types<Z<Ts...>>:types_t<Ts...>;
            template<class B>
            struct get_B_index;
            template<unsigned i, template<unsigned>class B>
            struct get_B_index<B<i>>:std::integral_constant<unsigned, i>;


            and from this we can get A's template arguments from B:



             template<class...Ts, unsigned i>
            void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var )

            template<class B>
            void foo( B b )
            using types = get_types_t< typename B::daddy >;
            using index = get_B_index< B >;
            return foo( types, index, b );



            Live example






            share|improve this answer























            • Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

              – tuket
              Nov 12 '18 at 22:15











            • "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

              – AnT
              Nov 12 '18 at 22:52












            • @tuket yes, I am. It is known as Halt.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:03











            • @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:06















            4














            Because the standard says so.



            The standard says so because inverting arbitrary compile time maps is equivalent to Halt.



            It is equivalent to Halt because template metaprogramming is Turing complete.



            It is Turing complete because it is actually hard to make a useful programming language that isn't Turing complete; it happens by accident, and avoiding it leads to a language that requires annoying workaround for seemingly simple things.



            So the problem in general, of determining which A the A<int, float>::B<0> is from and reversing that mapping, is hard, so the C++ standard says the compiler doesn't try.



            If you write your own mapping you can do it. First, you have to realize that B types have no "hair" in that there is nothing about the type of B that attaches it back to the type of A used to create it. We can add "hair":



            template<class...Ts>
            struct A
            template<unsigned i>
            struct B
            using daddy = A;
            int b;
            ;
            ;


            now we can find A from the type of B<?>.



            Next let's add some inverse maps:



             template<class...Ts>
            struct types_t using type=types_t;;

            template<class X>
            struct get_types;
            template<class X>
            using get_types_t=typename get_types<X>::type;
            template<template<class...>class Z, class...Ts>
            struct get_types<Z<Ts...>>:types_t<Ts...>;
            template<class B>
            struct get_B_index;
            template<unsigned i, template<unsigned>class B>
            struct get_B_index<B<i>>:std::integral_constant<unsigned, i>;


            and from this we can get A's template arguments from B:



             template<class...Ts, unsigned i>
            void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var )

            template<class B>
            void foo( B b )
            using types = get_types_t< typename B::daddy >;
            using index = get_B_index< B >;
            return foo( types, index, b );



            Live example






            share|improve this answer























            • Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

              – tuket
              Nov 12 '18 at 22:15











            • "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

              – AnT
              Nov 12 '18 at 22:52












            • @tuket yes, I am. It is known as Halt.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:03











            • @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:06













            4












            4








            4







            Because the standard says so.



            The standard says so because inverting arbitrary compile time maps is equivalent to Halt.



            It is equivalent to Halt because template metaprogramming is Turing complete.



            It is Turing complete because it is actually hard to make a useful programming language that isn't Turing complete; it happens by accident, and avoiding it leads to a language that requires annoying workaround for seemingly simple things.



            So the problem in general, of determining which A the A<int, float>::B<0> is from and reversing that mapping, is hard, so the C++ standard says the compiler doesn't try.



            If you write your own mapping you can do it. First, you have to realize that B types have no "hair" in that there is nothing about the type of B that attaches it back to the type of A used to create it. We can add "hair":



            template<class...Ts>
            struct A
            template<unsigned i>
            struct B
            using daddy = A;
            int b;
            ;
            ;


            now we can find A from the type of B<?>.



            Next let's add some inverse maps:



             template<class...Ts>
            struct types_t using type=types_t;;

            template<class X>
            struct get_types;
            template<class X>
            using get_types_t=typename get_types<X>::type;
            template<template<class...>class Z, class...Ts>
            struct get_types<Z<Ts...>>:types_t<Ts...>;
            template<class B>
            struct get_B_index;
            template<unsigned i, template<unsigned>class B>
            struct get_B_index<B<i>>:std::integral_constant<unsigned, i>;


            and from this we can get A's template arguments from B:



             template<class...Ts, unsigned i>
            void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var )

            template<class B>
            void foo( B b )
            using types = get_types_t< typename B::daddy >;
            using index = get_B_index< B >;
            return foo( types, index, b );



            Live example






            share|improve this answer













            Because the standard says so.



            The standard says so because inverting arbitrary compile time maps is equivalent to Halt.



            It is equivalent to Halt because template metaprogramming is Turing complete.



            It is Turing complete because it is actually hard to make a useful programming language that isn't Turing complete; it happens by accident, and avoiding it leads to a language that requires annoying workaround for seemingly simple things.



            So the problem in general, of determining which A the A<int, float>::B<0> is from and reversing that mapping, is hard, so the C++ standard says the compiler doesn't try.



            If you write your own mapping you can do it. First, you have to realize that B types have no "hair" in that there is nothing about the type of B that attaches it back to the type of A used to create it. We can add "hair":



            template<class...Ts>
            struct A
            template<unsigned i>
            struct B
            using daddy = A;
            int b;
            ;
            ;


            now we can find A from the type of B<?>.



            Next let's add some inverse maps:



             template<class...Ts>
            struct types_t using type=types_t;;

            template<class X>
            struct get_types;
            template<class X>
            using get_types_t=typename get_types<X>::type;
            template<template<class...>class Z, class...Ts>
            struct get_types<Z<Ts...>>:types_t<Ts...>;
            template<class B>
            struct get_B_index;
            template<unsigned i, template<unsigned>class B>
            struct get_B_index<B<i>>:std::integral_constant<unsigned, i>;


            and from this we can get A's template arguments from B:



             template<class...Ts, unsigned i>
            void foo( types_t<Ts...>, std::integral_constant<unsigned, i>, typename A<Ts...>::template B<i> var )

            template<class B>
            void foo( B b )
            using types = get_types_t< typename B::daddy >;
            using index = get_B_index< B >;
            return foo( types, index, b );



            Live example







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 12 '18 at 21:55









            Yakk - Adam NevraumontYakk - Adam Nevraumont

            184k19191376




            184k19191376












            • Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

              – tuket
              Nov 12 '18 at 22:15











            • "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

              – AnT
              Nov 12 '18 at 22:52












            • @tuket yes, I am. It is known as Halt.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:03











            • @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:06

















            • Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

              – tuket
              Nov 12 '18 at 22:15











            • "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

              – AnT
              Nov 12 '18 at 22:52












            • @tuket yes, I am. It is known as Halt.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:03











            • @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

              – Yakk - Adam Nevraumont
              Nov 13 '18 at 0:06
















            Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

            – tuket
            Nov 12 '18 at 22:15





            Thanks for your answer. I wasn't expecting it to get so complicated. When you say it's equivalent to Halt are you referring to the Halting problem?

            – tuket
            Nov 12 '18 at 22:15













            "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

            – AnT
            Nov 12 '18 at 22:52






            "there is nothing about the type of B that attaches it back to the type of A used to create it." Well, in general case this statement is incorrect. When you define a new nested type (a nested class definition, as is in this case), the nested type is uniquely and unambiguously attached to the enclosing type. The "no attachment" situation only appears when the nested type is an alias (e.g. a typedef name). The language spec simply does not want to distinguish between these two situations and instead opts for the "lowest common denominator".

            – AnT
            Nov 12 '18 at 22:52














            @tuket yes, I am. It is known as Halt.

            – Yakk - Adam Nevraumont
            Nov 13 '18 at 0:03





            @tuket yes, I am. It is known as Halt.

            – Yakk - Adam Nevraumont
            Nov 13 '18 at 0:03













            @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

            – Yakk - Adam Nevraumont
            Nov 13 '18 at 0:06





            @ant To be more explicit, in C++ code there is no way to go from a type A to the type it was defined in. The namespace it was defined in can be tricked out by injecting a helper function with a unique name into each namespace to test, then doing careful ADL. A way to do that could be added, but it isn't there.

            – Yakk - Adam Nevraumont
            Nov 13 '18 at 0:06













            2














            Template argument deduction can't deduce anything that appears in a nested-name-specifier. For example, it won't allow T to be deduced from a parameter of type typename Foo<T>::bar. I believe that the reason for this is that such deduction is not possible in general; there can always be partial specializations of Foo that define bar to be some arbitrarily complicated typedef.



            The workaround is to define the nested type as an unnested type then bring it in using a typedef, but use the original unnested name for deduction:



            template <unsigned i, typename... Ts>
            struct A_B int b;

            template <typename... Ts>
            struct A
            template <unsigned i> using B = A_B<i, Ts...>;
            ;

            template <unsigned i, typename... Ts>
            void foo(A_B<i, Ts...> var);





            share|improve this answer


















            • 1





              It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

              – SergeyA
              Nov 12 '18 at 21:58











            • Thanks, I like this solution because it's simple

              – tuket
              Nov 12 '18 at 22:17















            2














            Template argument deduction can't deduce anything that appears in a nested-name-specifier. For example, it won't allow T to be deduced from a parameter of type typename Foo<T>::bar. I believe that the reason for this is that such deduction is not possible in general; there can always be partial specializations of Foo that define bar to be some arbitrarily complicated typedef.



            The workaround is to define the nested type as an unnested type then bring it in using a typedef, but use the original unnested name for deduction:



            template <unsigned i, typename... Ts>
            struct A_B int b;

            template <typename... Ts>
            struct A
            template <unsigned i> using B = A_B<i, Ts...>;
            ;

            template <unsigned i, typename... Ts>
            void foo(A_B<i, Ts...> var);





            share|improve this answer


















            • 1





              It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

              – SergeyA
              Nov 12 '18 at 21:58











            • Thanks, I like this solution because it's simple

              – tuket
              Nov 12 '18 at 22:17













            2












            2








            2







            Template argument deduction can't deduce anything that appears in a nested-name-specifier. For example, it won't allow T to be deduced from a parameter of type typename Foo<T>::bar. I believe that the reason for this is that such deduction is not possible in general; there can always be partial specializations of Foo that define bar to be some arbitrarily complicated typedef.



            The workaround is to define the nested type as an unnested type then bring it in using a typedef, but use the original unnested name for deduction:



            template <unsigned i, typename... Ts>
            struct A_B int b;

            template <typename... Ts>
            struct A
            template <unsigned i> using B = A_B<i, Ts...>;
            ;

            template <unsigned i, typename... Ts>
            void foo(A_B<i, Ts...> var);





            share|improve this answer













            Template argument deduction can't deduce anything that appears in a nested-name-specifier. For example, it won't allow T to be deduced from a parameter of type typename Foo<T>::bar. I believe that the reason for this is that such deduction is not possible in general; there can always be partial specializations of Foo that define bar to be some arbitrarily complicated typedef.



            The workaround is to define the nested type as an unnested type then bring it in using a typedef, but use the original unnested name for deduction:



            template <unsigned i, typename... Ts>
            struct A_B int b;

            template <typename... Ts>
            struct A
            template <unsigned i> using B = A_B<i, Ts...>;
            ;

            template <unsigned i, typename... Ts>
            void foo(A_B<i, Ts...> var);






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Nov 12 '18 at 21:47









            BrianBrian

            64.3k795182




            64.3k795182







            • 1





              It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

              – SergeyA
              Nov 12 '18 at 21:58











            • Thanks, I like this solution because it's simple

              – tuket
              Nov 12 '18 at 22:17












            • 1





              It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

              – SergeyA
              Nov 12 '18 at 21:58











            • Thanks, I like this solution because it's simple

              – tuket
              Nov 12 '18 at 22:17







            1




            1





            It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

            – SergeyA
            Nov 12 '18 at 21:58





            It is simply not reasonably to deduce type in such contest. For starters, it is not necessarily one-to-one mapping.

            – SergeyA
            Nov 12 '18 at 21:58













            Thanks, I like this solution because it's simple

            – tuket
            Nov 12 '18 at 22:17





            Thanks, I like this solution because it's simple

            – tuket
            Nov 12 '18 at 22:17











            0














            In your specific case the nested type B is uniquely attached to the specific specialization of the enclosing type A. There's one-to-one correspondence between various Bs and their enclosing As. So, theoretically it should be possible to deduce the arguments of A from a specific B.



            However, in general case the nested type name might refer to an alias (e.g. typedef-name), as opposed to a genuinely new type name (as in your example). In case of nested alias the 1:1 correspondence no longer holds, which is demonstrated by the examples in other answers.



            The language specification does not distinguish between these two situations (a genuinely new nested type vs. a nested alias), so it opts for the "common denominator" approach and just always treats the enclosing template parameters as non-deduced context.






            share|improve this answer



























              0














              In your specific case the nested type B is uniquely attached to the specific specialization of the enclosing type A. There's one-to-one correspondence between various Bs and their enclosing As. So, theoretically it should be possible to deduce the arguments of A from a specific B.



              However, in general case the nested type name might refer to an alias (e.g. typedef-name), as opposed to a genuinely new type name (as in your example). In case of nested alias the 1:1 correspondence no longer holds, which is demonstrated by the examples in other answers.



              The language specification does not distinguish between these two situations (a genuinely new nested type vs. a nested alias), so it opts for the "common denominator" approach and just always treats the enclosing template parameters as non-deduced context.






              share|improve this answer

























                0












                0








                0







                In your specific case the nested type B is uniquely attached to the specific specialization of the enclosing type A. There's one-to-one correspondence between various Bs and their enclosing As. So, theoretically it should be possible to deduce the arguments of A from a specific B.



                However, in general case the nested type name might refer to an alias (e.g. typedef-name), as opposed to a genuinely new type name (as in your example). In case of nested alias the 1:1 correspondence no longer holds, which is demonstrated by the examples in other answers.



                The language specification does not distinguish between these two situations (a genuinely new nested type vs. a nested alias), so it opts for the "common denominator" approach and just always treats the enclosing template parameters as non-deduced context.






                share|improve this answer













                In your specific case the nested type B is uniquely attached to the specific specialization of the enclosing type A. There's one-to-one correspondence between various Bs and their enclosing As. So, theoretically it should be possible to deduce the arguments of A from a specific B.



                However, in general case the nested type name might refer to an alias (e.g. typedef-name), as opposed to a genuinely new type name (as in your example). In case of nested alias the 1:1 correspondence no longer holds, which is demonstrated by the examples in other answers.



                The language specification does not distinguish between these two situations (a genuinely new nested type vs. a nested alias), so it opts for the "common denominator" approach and just always treats the enclosing template parameters as non-deduced context.







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 12 '18 at 23:01









                AnTAnT

                258k32414657




                258k32414657



























                    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%2f53270480%2fwhy-cant-the-template-parameters-of-this-function-be-inferred-for-this-nested-t%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

                    Use pre created SQLite database for Android project in kotlin

                    Darth Vader #20

                    Ondo