Template Type Deduction in C++ for Class VS Function

Template type deduction in C++ for Class vs Function?

In specific cases you could always do like std::make_pair:

template<class T>
make_foo(T val) {
return foo<T>(val);
}

EDIT: I just found the following in "The C++ Programming Language, Third Edition", page 335. Bjarne says:

Note that class template arguments are
never deduced. The reason is that the
flexibility provided by several
constructors for a class would make
such deduction impossible in many
cases and obscure in many more.

This is of course very subjective. There's been some discussion about this in comp.std.c++ and the consensus seems to be that there's no reason why it couldn't be supported. Whether it would be a good idea or not is another question...

Function template argument deduction (class vs funtion template)

In the first case, you are explicitly instantiating the class template Test1. This means the function declaration for its add member is generated with the signature add(const std::function<void(int)>&). When the compiler subsequently tries to resolve test1.add(func), there is only that one candidate. Since std::function<void(int)> can be implicitly constructed from a void(int) function, the signatures match, the compiler just instantiates the member function definition and everything is good.

In the second case, the compiler has to perform template argument deduction/substitution to see if it can "use" the add template. You may think that specifying int would nail down the template parameters so that no deduction is necessary, but that is not the case: It could be that you mean to partially specify template arguments, see for example here. In other words, you might be trying to instantiate the function template with more parameters than you specified explicitly, at least the compiler doesn't know if you do. So it still has to try and match the types of std::function<void(ARGS...)> (or more precisely, std::function<void(int, ...)> and void(int), which it can't, because implicit conversions are not considered for the deduction.

In short: Specifying explicit template arguments does not prevent template parameter deduction for variadic function templates.

Note: I am not 100% firm with the exact terminology, any language lawyering to correct me is appreciated!

Edit: I am basing this primarily on what I read here.

Why is no deduction for template parameters only used as return type?

Generally it is not possible to deduce function based on its return type. But if you use automatic types conversion c++ feature then you could achieve what you need:

template <typename T>
T zero() { return 1; }

template <>
float zero<float>() { return 3.0f; }

struct Zero
{
template<typename T>
operator T()
{
return zero<T>();
}
};

int main()
{
int x = Zero();
float y = Zero();
return x + y;
}

First you create temporary object Zero(), and during assigment we use conversion operator to execute correct specialization of zero template function.

C++ funtion template deduction of type from member type?

It can't deduce T from float, which is what a is. It wont treat typedefs with any special consideration when trying to fill your template. It's also not going to search the whole type space for any type with a member by that name.

One way to get that deduction is to boost that member type with a reference to the owning class, and add an implicit conversion back to the primitive:

template <typename TOwner, typename TData>
class x_t {
TData data;
public:
constexpr x_t() = default;
constexpr x_t(TData data) : data(data) { }
constexpr operator TData() const { return data; }
};

struct A {
using x_t = x_t<A, float>;
/*...*/
};

Then partial specialization will work correctly:

template<typename TOwner, typename TData>
void fn(x_t<TOwner, TData> x) {
TOwner t;
t.whatami();
};

And you can use an instance in any type-safe function

A::x_t a(42.0);
std::cout << a; // 42.0

(sadly, printf doesn't count as type-safe. using streams here, fmt::printf from the excellent fmt library would also work).

It probably doesn't reach your goal of making it easy to deduce from a member, but it's a possibility.

Choose between template function and auto type deduction

The obvious reason for this particular code would be that they don't really have the same semantics at all.

In particular, if you pass arguments of different types, the version using auto will deduce a type independently for each, then based on those deduce a type for the result.

Conversely, with the template version, you've specified exactly one type, so the arguments must both be the same type (and the result will be the same).

So, to get the code to be more nearly equivalent, you'd really need to write the template more like:

template <class T, class U> 
auto add(T a, U b) -> decltype(a+b) {
return a+b;
}

This is obviously possible as well, but adds even more strength to the arguments in favor of using auto instead.

Class Template Argument Deduction for template dependent parameter

I think the answer is simple. In the first case, with the free function template, what kicks in first is overloading resolution and function template argument deduction. As the compiler has no way to detect T from the int passed as argument (clang says: candidate template ignored: could not match 'number<type-parameter-0-0>' against 'int'), the overloading resolution fails and the program is ill formed.

When the function is defined as friend, it's a non-template function. The compiler created it when instantiating the class (for number<int>; first line in main). Now, when it finds it (using ADL), the parameter types are already set (both are number<int> because it comes from number<int> instantiation), and what's left is to decide on how to convert the passed argument from int to number<int>, where the implicit conversion (by the matching c-tor) is used. No CTAD here either.

A similar (but not exactly the same) case is discussed by Scott Meyers in Effective C++ (3rd edition), Item 46: Define non-member functions inside templates when type conversions are desired.

Edit:
So to answer the question, function template argument deduction and implicit type conversion for the arguments can't be mixed. Choose one. (Which is what Meyers explains in the mentioned item.)

C++ function template type deduction from function parameter fails

All your questions have the same answer: the order of template parameter is important and, to explicate a template parameter, you have to explicate all template parameters before it.

When you write

template<typename C, Ret(C::* func)(ArgType)>
void connect(C& instance)

or

template<typename C, auto func>
void disconnect(C& instance)

the first template parameter can be deduced from instance, the second one can't be deduced so has to be explicated.

But, this is the problem, if you have to explicate a template parameter, you must explicate all template parameter before it.

So

signal.connect<&Window::kpEventHandler>(window); 

doesn't works because <&Window::kpEventHandler> explicate the first template parameter, that is C; and a &Window::kpEventHandler (that is a value) doesn't matches C, the first template argument (that has to be a type).

You have to explicate both template parameters, in the correct order, so

signal.connect<Window, &Window::kpEventHandler>(window);    
signal.disconnect<Window, &Window::kpEventHandler>(window);

Different if you place the non-deducible template parameter in first position

template<auto func, typename C>
void connect(C& instance)

This way you can explicate the first template parameter (the func value) and let the compiler to deduce C from the argument instance.

So you can write

signal.connect<&Window::kpEventHandler>(window);
signal.disconnect<&Window::kpEventHandler>(window);

but works also if you explicate the second template parameter too

signal.connect<&Window::kpEventHandler, Windows>(window);
signal.disconnect<&Window::kpEventHandler, Windows>(window);


Related Topics



Leave a reply



Submit