Deriving a template argument from a function body

If we have this function template,

template<typename T>
void f(T param) {}

Then we can call it in the following ways:

int i=0;
f<int>(i);//T=int : no need to deduce T
f(i); //T=int : deduced T from the function argument!

//likewise
sample s;
f(s); //T=sample : deduced T from the function argument!

Now consider this variant of the above function template,

template<typename TArg, typename TBody>
void g(TArg param) 
{
   TBody v=param.member;
}

Now, can the compiler output the template arguments if we write

sample s;
g(s); //TArg=sample, TBody=int??

Suppose that sampleis defined as <

struct sample
{
   int member;
};

There are basically two questions:

  • Can the compiler output the template arguments in the second example?
  • If not, why? Are there any difficulties? If the standard does not say anything about “deducing a template argument from the function body”, is that because the argument cannot be deduced? Or did he not take such deduction into account so as not to increase the complexity of the language? Or what?

I would like to know your opinions on this conclusion.


EDIT:

By the way, GCC can output function arguments if we write this code:

template<typename T>
void h(T p)
{
        cout << "g() " << p << endl;
        return;
}
template<typename T>
void g(T p)
{
        h(p.member); //if here GCC can deduce T for h(), then why not TBody in the previous example?
        return;
}

: http://www.ideone.com/cvXEA

: http://www.ideone.com/UX038

+3
4

, , , TBody, sample.member. .

, . , :

template <typename T> void f(T param);

. , , , - , . , . , :

template <> void f(int param);

, , , 2- :

template<typename TArg, typename TBody>
void g(TArg param, TBody body = param.member);  // won't deduce TBody from TArg

, . , , -, . ? .. ?

, , , .

:

struct sample
{
   typedef int MemberType;
   MemberType member;
};

template<typename TArg>
void g(TArg param) 
{
   typename TArg::MemberType v = param.member;
}

sample s = { 0 };
g(s);

.


, : , h(p.member) , , , , , :

  • g(s); , sample ( !). - void g(T p). g(T p)!.
  • g(T p), T: sample. , h(p.member), , p.member int h() int. h(T p).

, ( NOT_A_member):

template<typename T>
void g(T p)
{
        h(p.NOT_A_member);
        return;
}

g() 1. , , sample , NOT_A_member.

+5

. .

0

TBody , sample , member. , g , , TBody.

, TBody, , .

0

, , , TBody. -, , . .

, , TBody v = parameter.member , , parameter.member .

, . , , g(x) . , template <typename T> void g( T ) , T . , , .

, T , p . , , . p.member, p T, , , ( , , typename). h(p.member); T , , , , , .

. T , sample. , . p.member, member , int, h( p.member ); . T , g(x): , , h, int&, , h ...

For metaprogramming, it is very important to understand that type inference is performed only by the actual signature of the function, and not by the body, and this is what makes it non-trivial for beginners. Using enable_if(from boost or elsewhere) in the function signature as an argument or return type is not a coincidence, but the only way that the compiler cannot replace the type before the template is selected as the best candidate and the replacement failure turns into an actual error (not SFINAE)

0
source

Source: https://habr.com/ru/post/1787811/


All Articles