views:

654

answers:

4

While reading another question, i came to a problem with partial ordering, which i cut down to the following test-case

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

int main() {
  // GCC chokes on f(0, 0) (not being able to match against T1)
  void *p = 0;
  f(0, p);
}

For both function templates, the function type of the specialization that enters overload resolution is void(int, void*). But partial ordering (according to comeau and GCC) now says that the second template is more specialized. But why?

Let me go through partial ordering and show where i have questions. May Q be an unique made-up type used for determining partial ordering according to 14.5.5.2.

  • Transformed parameter-list for T1 (Q inserted): (Q, typename Const<Q>::type*). The types of the arguments are AT = (Q, void*)
  • Transformed parameter-list for T2 (Q inserted): BT = (Q, void*), which are also the types of the arguments.
  • Non-transformed parameter-list for T1: (T, typename Const<T>::type*)
  • Non-transformed parameter-list for T2: (T, void*)

Since C++03 under-specifies this, i did use the intention that i read about in several defect reports. The above transformed parameter list for T1 (called AT by me) is used as argument list for 14.8.2.1 "Deducing template arguments from a function call".

14.8.2.1 does not need to transform AT or BT itself anymore (like, removing reference declarators, etc), and goes straight to 14.8.2.4, which independently for each A / P pair does type deduction:

  • AT against T2: { (Q, T), (void*, void*) }. T is the only template parameter here, and it will find that T must be Q. Type deduction succeeds trivially for AT against T2.

  • BT against T1: { (Q, T), (void*, typename Const<T>::type*) }. It will find that T is Q, too here. typename Const<T>::type* is an un-deduced context, and so it won't be used to deduce anything.


Here is my first question: Will this now use the value of T deduced for the first parameter? If the answer is no, then the first template is more specialized. This can't be the case, because both GCC and Comeau say that the second template is more specialized, and i don't believe they are wrong. So we assume "yes", and insert void* into T. The paragraph (14.8.2.4) says "Deduction is done independently for each pair and the results are then combined" and also "In certain contexts, however, the value does not participate in type deduction, but instead uses the values of template arguments that were either deduced elsewhere or explicitly specified." This sounds like "yes" too.

Deduction therefore succeeds too, for every A / P pair. Now, each template is at least as specialized as the other, because deduction didn't also rely on any implicit conversions and succeeded in both directions. As a result, the call should be ambiguous.

So my second question: Now, why do the implementations say that the second template is more specialized? What point did i overlook?


Edit: I tested explicit specialization and instantiation, and both, in recent GCC versions (4.4) tell me that the reference to the specialization is ambiguous, while an older version of GCC (4.1) doesn't rise that ambiguity error. This suggests that recent GCC versions have inconsistent partial ordering for function templates.

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

template<> void f(int, void*) { }
  // main.cpp:11: error: ambiguous template specialization 
  // 'f<>' for 'void f(int, void*)'
+1  A: 

Transformed parameter-list for T1 (Q inserted): (Q, typename Const::type*). The types of the arguments are AT = (Q, void*)

I wonder if that really is a correct simplification. When you synthesise the type Q, are you allowed to conjure up a specialization for Const for the purposes of determining the ordering of template specliazation?

template <>
struct Const<Q> { typedef int type; }

This would imply that T2 is not at least as specialized as T1 because a void* parameter does not match T1's second parameter for any given template parameters.

Charles Bailey
The type "Q" is unique and synthesized by the compiler, for that purpose only (i think that's what they mean with "unique") and has no name. We can't use it to define that specialization. I'm not sure either whether the simplification i made is valid. But we have to get an argument type. So to see what type `typename Const<Q>::type` is, one has to look into `Const<Q>`. *"T1 is more specialized because a void* parameter does not work for T1's second parameter for all template parameters T."*: But GCC and Comeau disagree with this :( They say T2 is more specialized, ...
Johannes Schaub - litb
... even if i put a specialization of "Const", for say "int".
Johannes Schaub - litb
You're right; I'm wrong. I was 'allowing' implicit coversions to void* from other types in the determination of 'at least as specialized' in 14.5.5.2/4. I'm still not sure how either of them is at least as specialized as the other, though.
Charles Bailey
@litb: Why do you feel that "we have to get an argument type"? I think this could be where the error in logic is coming in.
Richard Corden
@Richard, because without a type, we cannot do any type deduction. So `14.8.2.4/1` says *"Template arguments can be deduced in several different contexts, but in each case a type that is specified in terms of template parameters (call it P) is compared with an actual type (call it A),..."*. `Const<Q>::type` is just another syntax (qualified-id) for the type `void` (simple-type-specifier). `Const<Q>::type` is not dependent either, so this can't be a case of *"it doesn't equal to any other type yet because it's dependent"*.
Johannes Schaub - litb
+1  A: 

Edit: After studying Clang's implementation (by Doug Gregor) of their partial ordering algorithm, I have come to agree with the rest of the posters that the original example is not 'intended' to be ambiguous - even though the standard is not as clear as it could be about what should happen in such situations. I have edited this post to indicate my revised thoughts (for my own benefit & reference). In particular Clang's algorithm clarified that 'typename Const<T>::type' is not translated into 'void' during the partial ordering step - and that each A/P pair is deduced independent of each other.

Initially I wondered why the following was considered ambiguous:

        template<class T> void f(T,T*);  // 1

        template<class T> void f(T, int*); // 2

        f(0, (int*)0); // ambiguous

(The above is ambiguous because one cannot deduce f1(U1,U1*) from f2(T,int*), and going the other way, one cannot deduce f2(U2,int*) from f1(T,T*). Neither is more specialized.)

but the following would not be ambiguous:

        template<class T> struct X { typedef int type; };
        template<class T> void f(T, typename X<T>::type*); // 3
        template<class T> void f(T, int*); // 2

(The reason one could expect it to be ambiguous is if the following were to happen:
- f3(U1,X<U1>::type*) -> f3(U1, int*) ==> f2(T,int*) (deduction ok, T=U1)
- f2(U2,int*) ==> f3(T, X<T>::type*) (deduction ok, T=U2 makes X<U2>::type* -> int*)
If this were true, neither one would be more specialized than the other.)

After studying Clang's partial ordering algorithm it is clear that they treat '3' above as if it was:

template<class T, class S> void f(T, S*); // 4

so deduction of some unique 'U' against 'typename X::type' will succeed -

  • f3(U1,X<U1>::type*) is treated as f3(U1, U2*) ==> f2(T,int*) (deduction not ok)
  • f2(U2,int*) ==> f3(T,S* [[X<T>::type*]]) (deduction ok, T=U2, S=int)

And so '2' is clearly more specialized than '3'.

Faisal Vali
good point. i don't understand either how it makes a difference when putting the `X<T>` in between.
Johannes Schaub - litb
+1  A: 

Edit: Please disregard this post - After studying clangs algorithm for partial ordering as implemented by Doug Gregor (even though it is only partially implemented as of this writing - it seems that the logic that's relevant to the OP's question is implemented adequately enough) - it appears as if it treats the undeduced context as just another template parameter. Which suggests that the overload with the explicit void* argument should be the more specialized version and there should be no ambiguity. As usual Comeau is correct. Now as for the wording in the standard that clearly defines this behavior - that's another matter ...

Since this post was also posted on comp.lang.c++.moderated, and seems to be causing some confusion there too - i thought i'd post my answer to that group here too - since the discussion is obviously relevant to the question asked here.

On Jul 25, 1:11 pm, Bart van Ingen Schenau <[email protected]> wrote:

You are going one step too fast here. How do you know (and would the compiler know) that there is no specialisation of Const<Q> such that Const<Q>::type != void?

As far as I can see, the compiler would transform the parameter-list of A to: AT=(Q, <unknown>*). To call B with these parameters requires an implicit conversion (<unknown>* to void*) and therefore A is less specialised than B.

I believe this is incorrect. When checking to see which function is more specialized (during partial-ordering), the compiler transforms the parameter-list to (Q, void*) - i.e. it actually instantiates the relevant template (best matching) and looks inside it for the value of 'type' - in this case, based on the primary template, it will be void*.

Regarding your point concerning partial specialization - when checking for which template is more specialized than the other, the only type that can be used is the unique generated type - if there are other specializations at the point of instantiation of the declaration (when overload resolution is being done) they will be considered. If you add them later, and they should get selected you will be violating the ODR (according to 14.7.4.1)

The partial/explicit specializations will also get considertaion during formation of the candidate set - but this time using the types of the actual arguments to the function. If the best matching partial specialization (of X) results in a function type that has a better implicit conversion sequence for some parameter, then we never make it to the partial-ordering phase, and that "better" function will get selected (before making it to the partial ordering phase)

Here is an example with comments about what should be going on at various steps:

    template<class T, bool=true> struct X;  // Primary

    template<class T> struct X<T,true> { typedef T type; };  // A
    template<> struct X<int*,true> { typedef void* type; };  // B


    template<class T> void f(T,typename X<T>::type); //1
    template<class T> void f(T*,void*); //2


    int main()
    {
      void* pv;
      int* pi;


      f(pi,pi);   
      // two candidate functions: f1<int*>(int*,void*),  f2<int>(int*,void*)
      // Note: specialization 'B' used to arrive at void* in f1
      // neither has a better ICS than the other, so lets partially order
      // transformed f1 is f1<U1>(U1,X<U1,true>::type) --> f1<U1>(U1,U1) 
      //       (template 'A' used to get the second U1)
      // obviously deduction will fail (U1,U1) -> (T*,void*)
      // and also fails the other way (U2*, void*) -> (T,X<T>::type)
      // can not partially order them - so ambiguity 




      f(pv,pv);  
      // two candidate functions: f1<void*>(void*,void*), f2<void>(void*,void*)
      // Note: specialization 'A' used to arrive at second void* in f1
      // neither has a better ICS than the other, so lets partially order
      // transformed f1 is f1<U1>(U1,X<U1>::type) --> f1<U1>(U1,U1) 
      //       (template 'A' used to get the second U1)
      // obviously deduction will fail (U1,U1) -> (T*,void*)
      // and also fails the other way (U2*, void*) -> (T,X<T>::type)
      // can not partially order them - so ambiguity again             

    }

It's also worth mentioning that if the primary template does not have a definition - then SFINAE operates during the partial ordering phase, neither can be deduced from the other, and ambiguity should result.

Also if you add another template that would lead to another match if the point of instantation of either of those functions is moved elsewhere in the translation unit you will clearly violate the ODR.

On Jul 25, 1:11 pm, Bart van Ingen Schenau <[email protected]> wrote:

First, being more specialised means that these are fewer types where that template can be selected by overload resolution. Using this, the rules for partial ordering can be summarised as: Try to find a type for A such that A can be called but B not, or overload resolution prefers to call A. If that type can be found, then B is more specialised than A.

No argument here. But based on the rules as they are currently, the OP's example has to be ambiguous.


Finally, here are explicit, unambiguous answers to the two specific questions raised by litb:

1) Will this now use the value of T deduced for the first parameter?
Yes - of course, it has to, it is doing template argument deduction - the 'links' have to be maintained.

2) Now, why do the implementations say that the second is more specialized instead?
Because they are wrong ;)

I hope this puts the issue to rest - Please let me know if there is anything that is still unclear :)

Edit: litb raised a good point in his comment - perhaps stating that the primary template will always get used for the instantiation with the unique generated type is too strong a statement.
There are instances where the primary template will not be called.
What I am getting at is that when partial ordering is occuring, some unique generated type is used to match the best specialization. You're right, it doesn't have to be the primary template. I have edited the above language to do so. He also raised an issue regarding defining a better matching template after the point of instantation. That will be a violation of the ODR according to the section on point of instantiation.


The standard says that once the A/P pairs are created (using the rules of transformation as described in temp.func.order) they are deduced against each other using template argument deduction (temp.deduct)- and that section handles the case of non-deduced contexts, instantiating the template and its nested type, triggering points of instantiations. The temp.point section handles the ODR violations (the meaning of partial ordering should not change regardless of the points of instantation within a translation unit). I'm still not sure where the confusion is coming from? – Faisal Vali 1 hour ago [delete this comment]

litb: "Note that the step that puts Q into Const::type to build the arguments is not covered explicitly by the SFINAE rule. The SFINAE rules work with argument deduction, put the paragraphs that put Q into the function template function parameter list are at 14.5.5.2.'

The SFINAE rules have to be used here - how could they not be? I feel it is sufficiently implied - i won't deny that it could be clearer, and while i encourage the committee to clarify this - i don't think it needs to be clarified to interpret your example sufficiently.

Let me provide one way to link them. From (14.8.2): "When an explicit template argument list is specified, the template arguments must be compatible with the template parameter list and must result in a valid function type as described below; otherwise type deduction fails"

From (14.5.5.2/3) "The transformation used is: — For each type template parameter, synthesize a unique type and substitute that for each occurrence of that parameter in the function parameter list, or for a template conversion function, in the return type."

In my mind, the above quote implies that once you "create" unique generated types for each template parameter, the function declaration has to be implicity instantiated by explicitly supplying the unique types as template arguments to our function template. If this results in an invalid function type, then not only the transformation, but more importantly the subsequent template argument deduction necessary to partially order the function fails.

From (14.5.5.2/4) "Using the transformed function parameter list, perform argument deduction against the other function template. The transformed template is at least as specialized as the other if, and only if, the deduction succeeds and the deduced parameter types are an exact match (so the deduction does not rely on implicit conversions)."

If the transformed function parameter list leads to substitution failure, then we know deduction could not have succeeded. And since deduction did not succeed, it is not as specialized as the other - that is all we need to know to proceed in partial ordering the two.

litb: I'm also not sure what happens in this case: template<typename T> struct A; template<typename T> void f(T, typename A<T>::type); template<typename T> void f(T*, typename A<T>::type); surely, that's indended to be valid code, but doing A::type, it will fail because at the template definition context, A isn't defined yet" Also note that there is no POI defined for template instantiations resulting from this kind of substitution while trying to determine an ordering (partial ordering does not depend on any context. It's a static property of two function templates involved). I think this looks like a problem in the Standard which needs to be fixed.

Ok - i think i see where we are seeing things differently. If i understand you correctly, you are saying that as these function templates get declared, the compiler is keeping a track of the partial ordering amongst them, regardless of overload resolution ever getting triggered to select between them. If that is how you interpret it, then i can see why you would expect the above behavior you describe. But I do not think that the standard ever requires or mandates that.

Now, the standard is clear that the partial ordering is agnostic to the type that is used in calling the function (I believe this is what you are referring to when you describe it as a static property and it being context independent).

The standard is also clear that it only cares about partial ordering (invokes partial ordering) between function templates during the process of overload resolution (13.3.3/1) if and only if it could not pick the better function based on ICS's or if one is a template and the other is not. [Partial ordering of class template partial specializations is a separate issue and in my mind uses the relevant context (other template definitions) that requires the instantiation of that particular class.]

Thus, in my opinion, since the machinery of partial ordering of function templates is invoked when overload resolution is performed, it has to use a relevant portion of the context (template definitions and specializations) available at the point when the overload resolution is being done.

So based on my interepretation, according to your example using 'template struct A' above, the code is valid. The partial ordering is not done at the definition context. But if/when you happen to invoke overload resolution between the two functions by writing a call to f((int*)0,0) - and at that time when the compiler either tries to assemble a candidate declaration or partially order them (if it gets to the partial-ordering step) if an invalid expression or type results as part of the function type, SFINAE helps us out and tells us that template deduction fails (as far as partial ordering is concerned, that implies that one cannot be more specialized than the other if we could not even transform the template).

Now as regards POIs - if you are convinced, as I am, that the transformed function types are supposed to represent implicit instantiations using explicitly supplied template argument lists (using the uniquely generated types) then the following standard quotes are relevant:

14.6.4.1/1 For a function template specialization, a member function template specialization, or a specialization for a member function or static data member of a class template, if the specialization is implicitly instantiated because it is referenced from within another template specialization and the context from which it is referenced depends on a template parameter, the point of instantiation of the specialization is the point of instantiation of the enclosing specialization.

The way I interpret this is that the POI of the transformed function type and the origianl function type is the same as the POI for those functions created by the actual function call.

litb: Since partial ordering is rather only a property of the syntactic form of parameters (i.e "T*" against "T(*)[N]"), i would vote for amending the specification (like "if Q appears in a nested name specifier of a qualified-id naming a type, then the type named is "Q") Or saying that the type named is another unique type. This means that in template<typename T> void f(T, typename Const<T>::type*); the argument list is (Q, R*), for example. Same for template<typename T> void f(T*, typename ConstI<sizeof(T)>::type); the arg lisst would be (Q*, R). A similar rule would be needed for non-type parameters, of course. I would have to think about it and make some test cases to see if this would yield natural orderings, though.

Aah - now you are suggesting a possible solution that resolves the ambiguity in favor of what we all intuitively expect - this is a separate problem, and while I like the direction you are heading in, like you, I too would have to put some thought into it before proclaiming its workability.

Thanks for continuing the discussion. I wish SO didn't just limit you to placing comments.

Since you can edit my posts, please feel free to respond within the post if that is easier.

Faisal Vali
Why will it use always the primary template? Have you got a quote of the Standard for that? Consider:`template<typename T, bool = true> struct X; template<typename T> struct X<T, true> { typedef void *type; };` In this case, the partial specialization matches and would be used for `Q`. I think what Bat van Ingen was after is, what happens when there is another specialization *after* the definition of the function template. Partial ordering can't consider it, since it doesn't know about it yet. But later references to a specialization will consider it.
Johannes Schaub - litb
But i don't see the Standard saying anything what happens in this case. :(
Johannes Schaub - litb
The standard says that once the A/P pairs are created (using the rules of transformation as described in temp.func.order) they are deduced against each other using template argument deduction (temp.deduct)- and that section handles the case of non-deduced contexts, instantiating the template and its nested type, triggering points of instantiations. The temp.point section handles the ODR violations (the meaning of partial ordering should not change regardless of the points of instantation within a translation unit). I'm still not sure where the confusion is coming from?
Faisal Vali
Note that the step that puts `Q` into `Const<T>::type` to build the arguments is not covered explicitly by the SFINAE rule. The SFINAE rules work with argument deduction, put the paragraphs that put `Q` into the function template function parameter list are at 14.5.5.2. I'm also not sure what happens in this case: `template<typename T> struct A; template<typename T> void f(T, typename A<T>::type); template<typename T> void f(T*, typename A<T>::type);` surely, that's indended to be valid code, but doing `A<Q>::type`, it will fail because at the template definition context, `A` isn't defined yet
Johannes Schaub - litb
Also note that there is no POI defined for template instantiations resulting from this kind of substitution while trying to determine an ordering (partial ordering does not depend on any context. It's a static property of two function templates involved). I think this looks like a problem in the Standard which needs to be fixed. Since partial ordering is rather only a property of the syntactic form of parameters (i.e "T*" against "T(*)[N]"), i would vote for amending the specification (like "if Q appears in a nested name specifier of a qualified-id naming a type, then the type named is "Q")
Johannes Schaub - litb
Or saying that the type named is another unique type. This means that in `template<typename T> void f(T, typename Const<T>::type*);` the argument list is `(Q, R*)`, for example. Same for `template<typename T> void f(T*, typename ConstI<sizeof(T)>::type);` the arg lisst would be `(Q*, R)`. A similar rule would be needed for non-type parameters, of course. I would have to think about it and make some test cases to see if this would yield natural orderings, though.
Johannes Schaub - litb
ok edited my post to address some of the excellent comments you made.
Faisal Vali
The type system in C++ is able to handle specializations involving dependent types (in fact it needs to). As a result there is no need for "Const<Q>::Type*" to be instantiated to "void*".
Richard Corden
@Richard Corden, after placing `Q` into `typename Const<T>::Type*`, we don't have a dependent type anymore. `Const<Q>::type` does not contain a template parameter anymore.
Johannes Schaub - litb
+3  A: 
Richard Corden
`Const<Q>::Type*` is `void*`. Just another way to name it. If it is another type, then what type is it? So `Const<Q>::Type` is a qualified-id naming `void` (in this case), so `void*` matches `void*` wonderfully and makes them "compatible".
Johannes Schaub - litb
@litb: I don't agree. What if there was an explicit specialization of Const where T was int? Is it correct that we always choose the primary template?
Richard Corden
Then `Const<Q>::Type*` would be `int*`. But in our case (in this case :)) it's `void*`.
Johannes Schaub - litb
See this example: `template<typename T> struct A { typedef int type; };` You say that `A<bool>::type` is not the type `int`.
Johannes Schaub - litb
@litb: No, I'm not saying that `A<bool>::type` is not int, because 'bool' is not a synthesized type. The only question here is does the compiler perform an instantiation with this synthesized type or does it just stick with a type of the form `Const<Q>::type`. I say the latter - and Comeau and g++ agree with me! :)
Richard Corden
Consider where you have two function declarations of the form: `void foo (typename Const<Q>::type)`. The compiler is not supposed to look inside the definition of `Const` to see what `type` really is, so it has to create an internal `DependentNestedNameType`. It then uses that type to match declarations of foo etc. I believe that process is very similar in this case. You don't know what Q really is, so you cannot know which specialization of `Const` to choose.
Richard Corden
But the Standard does not make a synthesized type dependent. It doesn't even define "synthesized type" (in fact i argue that any type is synthesized by the compiler - we just provide descriptions using declarations) :) Thus, `Const<Q>::type` is a non-dependent type `void`. It doesn't need to instantiate always: In case we provided an explicit specialization of `Const` that matches, no instantiation is needed. But in other case, because of name lookup, it surely needs to instantiate `Const<Q>` to get a type. I don't see any ambiguity on that part of the Standard :)
Johannes Schaub - litb
@Richard, sure the compiler has to look inside `Const<Q>` to see what type `::type` is, and to see whether an overload is valid or not (re-definition). Try "`void foo(A<bool>::type) { }` you will see that `A<bool>` is being instantiated at that point. This does not happen for dependent types of course: `template<typename T> void foo(typename Const<T>::type);` no instantiation happens unless `foo` enters overload resolution with a concrete `T`. But `Const<Q>::type` is not dependent :)
Johannes Schaub - litb
@litb: The standard may not say that the synthesized type is dependent, but it also doesn't say that it isn't. And what about my updated exmaple? What should `type` resolve to there? long or void? The more I consider it, you definitely don't want the synthesized type to result in an instantiation. Consider where you had a recursive template? (I'll add an example)...
Richard Corden
It's not specified what declarations partial ordering chooses, because the Standard provides no context (and no context is considered to be used for partial ordering, of course. It's a property of the function templates itself). In your case, `::type` for `Q` is not available, but the Standard IMHO is silent on the consequences. Therefor, i consider this a bug in the Standard. I proposed some solution in the comments to @Faisals answer, but i found my proposal to have some unwanted consequences. Further "drafting" needed :)
Johannes Schaub - litb
I think the recursive instantiation might be the key to this. If the comipler does instantiate the type then we would have the situation where partial ordering could result in different results dependening on the synthesized type chosen. This would completely break portability since different compilers could decide to choose completely different types (eg. EDG uses int[100], VC uses int[1], G++ uses int[10000]).
Richard Corden
BTW, +1 for your Update2 and the good discussion. You made me feel more certain that there surely is a BUG in the Standard about all this
Johannes Schaub - litb
+1 @RC - heh - that's an interesting example - a "unique" non-type value can indeed be unintentionally fully specialized for (not true for types) - the easiest (and most limiting) fix would be to state that if another "unique" value would result in a different partial ordering, the code is undefined - infinite recursion leads to undefined behavior anyways - but, in the end, i agree, the crack seems to run deep ...
Faisal Vali
... I would prefer a solution that can create the "best" partial ordering or best match based on the simple principle: if two function templates are equally viable until the partial-ordering step, then that which *theoretically* can match the fewest possible combinations of arguments be picked as the best candidate.
Faisal Vali
@Richard, i just checked clang, and it actually does not synthesize any type! It just uses the original function template parameter list with the dependent types in it. So it ignores the whole "a unique type, value or template is substituted..." part. "unique type" and "unique value" in the standard seems to be identical with "dependent type" and "type dependent expression" respectively. Not sure what "unique template" corresponds to, though. But this will explain why `Const<Q>::type` is *not* regarded as being void.
Johannes Schaub - litb
@litb - heh i was just about to post a very similar comment about clangs algorithm (since gregor just implemented it over the past week) - it also treats your example of the undeduced context as if it was replaced by a separate template parameter - i.e template<class T> void f(T,typename X<T>::type) is treated as template<class T, class U> void f(T,U)
Faisal Vali