1

I am playing around with ways to filter types passed to overloaded function templates. I'm using Visual Studio 2013.

Three part question:

  1. Why cant my compiler deduce Blorg3?
  2. Is the reason that TFoo2(argc) generates a compiler error the same as #1?
  3. Is there a way to pass template parameters to a constructor?

Here is the sample code:

#include <type_traits> #define IFPTR(T,R) typename std::enable_if<std::is_pointer<T>::value, R>::type #define IFINT(T,R) typename std::enable_if<std::is_integral<T>::value, R>::type template <class T, IFINT(T, T)* = nullptr> int Blorg1(T n) { return n + 1; } template <class T, IFPTR(T, T)* = nullptr> int Blorg1(T n) { return *n + 1; } template <class T> IFINT(T, int) Blorg2(T n) { return n + 1; } template <class T> IFPTR(T, int) Blorg2(T n) { return *n + 1; } template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; } template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; } struct TFoo1 { template <class T, IFINT(T, T)* _ = nullptr> TFoo1(T n) { } }; struct TFoo2 { template <class T> TFoo2(IFINT(T, T) n) { } }; int main(int argc, char* argv[]) { Blorg1(argc); // intellisense not happy Blorg2(argc); Blorg3<int>(argc); // why cant deduce? Blorg1(*argv); // intellisense not happy Blorg2(*argv); Blorg3<char*>(*argv); // why cant deduce? (void)TFoo1(argc); // intellisense not happy (void)TFoo2(argc); // intellisense not happy and !!wont compile!! return 0; } 
1
  • 2
    1. Because the template parameter only appears inside a nested-name-specifier, which is a non-deduced context (i.e. causes that template parameter not to be deduced from arguments to that particular parameter) 2. yes 3. no Commented Jan 19, 2015 at 21:09

2 Answers 2

2

Why cant my compiler deduce Blorg3?

In std::enable_if<std::is_pointer<T>::value, R>::type the ::type refers to a nested name that is dependent on the template parameters T and R. This is a non-deduced context (§14.8.2.5/5), consequently the compiler won't deduce the template argument.

Is that why TFoo2(argc) generates a compiler error?

Yes, a constructor template must be able to deduce its template arguments, and in this case it can't.

Is there a syntax to provide template parameters to a constructor?

No, as I already mentioned, you cannot do so explicitly, they must be deduced, or the template parameters must have default arguments.

Sign up to request clarification or add additional context in comments.

5 Comments

@MichaelGazonda I don't understand what you mean
"Is there a syntax to provide template parameters to a constructor?" - Yes, deduction will do that. It wasn't specified whether or not passing was required to be explicit or not... just that it needed to be done.
@MichaelGazonda Ok, agreed, but given the context of the earlier question, it seemed clear to me that the OP was asking about specifying the template arguments for the constructor explicitly.
What is the correct way to say what I meant? I thought "deduce" was what the compiler had to do when you were not explicit with <>.
@johnnycrash That is indeed what deduction means, in this case it is prohibited. I think your wording is clear enough, but if you want to change it, you could say provide template parameters explicitly to a constructor
2

Answer for 1/2 about the reason SFINAE isn't working:

SFINAE and template parameter deduction don't play well together in this context.

Or, they do so long as you're aware of the proper order things happen in.

The deduction must be guaranteed to work to be considered as a possible function to be called in this instance.

Here's a way to look at this in a less technical way:

  1. The compiler searches possible function signatures that match what you're trying to call. [see overload resolution]

  2. If it finds a template parameter, it looks to see if it's valid for deduction.

And this is why you're running into problems. The order in which these two events occur is why what SFINAE works on Blorg1, Blorg2 and TFoo1 but not Blorg3 or TFoo2.

With Blorg3 and TFoo2 the compiler can't slot the parameter you're passing to the template type as it creates a circular dependancy that can't be resolved.

template <class T> int Blorg3(IFINT(T, T) n) { return n + 1; } template <class T> int Blorg3(IFPTR(T, T) n) { return *n + 1; } Blorg3<char*>(*argv); // why cant deduce? 

To resolve the SFINAE in Blorg3 here requires knowing T. However, T isn't known until the SFINAE is resolved.

The same goes for why TFoo2 doesn't work.

Part 3 - about templates and constructors

Yes, you can pass template parameters to constructors, but only if you do it through deduction such as what was done with TFoo1.

You cannot explicitly pass template parameters to a constructor.

1 Comment

Thanks for explaining it! Since overload resolution ignores the return type, both Blorg1's will match the signature check. The template parameter is easily deducable for both blorg1's and 2 blorg1's are generated given the type. One of the functions fails the subsequent syntax check. blorg2 works the same way. When the non deduceable version blorg3 is reached, it doesn't generate a function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.