Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit template type deduction with two arguments of different types

Assume the following situation:

Type A and type B, B can be implicitly converted to A but the opposite is untrue.

I have a function

template<class T>
void do_stuff(T a, T b);

I want to call said function as such:

do_stuff(A{}, B{});

The problem here is that the compiler can't deduce the type and instead says:

template argument deduction/substitution failed

I can call my function like this:

do_stuff<A>(A{}, B{});

But this is more annoying for the user.

Alternatively I can do something like this:

template<class T, class M>
void do_stuff(T a, M b);

But then b goes on its merry way to be of type B (with the prior invocation).

Ideally I would like something like:

template<class T, class M = T>
void do_stuff(T a, M b);

Or:

template<class T@INSERT MAGIC SO THAT T IS DEDUCED AS BEING THE TYPE OF ARGUMENT NR 1@>
void do_stuff(T a, T b);

Is such a thing possible ?

like image 369
George Avatar asked Jun 29 '17 20:06

George


People also ask

What is template argument deduction?

Template argument deduction is used in declarations of functions, when deducing the meaning of the auto specifier in the function's return type, from the return statement.

How can we use more than one argument with a function template?

When argument is more than one, they are separated by commas. Test test1 (1.23, 123); tells the compiler that the first argument is of type float and another one is int type. During creation of objects, constructor is called and values are received by template arguments.

What is function templates C++ with multiple parameters with suitable example?

Function Templates with Multiple Parameters You can also use multiple parameters in your function template. The above syntax will accept any number of arguments of different types. Above, we used two generic types such as A and B in the template function.

What is type deduction C++?

Type inference or deduction refers to the automatic detection of the data type of an expression in a programming language. It is a feature present in some strongly statically typed languages. In C++, the auto keyword(added in C++ 11) is used for automatic type deduction.


3 Answers

Wrap b in a non-deduced context. That way, only a will be deduced and b must be converted to that type.

template <class T> struct dont_deduce { using type = T; };
template <class T> using dont_deduce_t = typename dont_deduce<T>::type;

template<class T>
void do_stuff(T a, dont_deduce_t<T> b);
like image 58
Barry Avatar answered Oct 24 '22 05:10

Barry


There is answer in C++11: std::common_type http://en.cppreference.com/w/cpp/types/common_type

template<typename A>
void f_impl(A a, A b)
{

}

template<typename A, typename B>
void f(A a, B b)
{
    f_impl<typename std::common_type<A, B>::type>(a, b);
}


struct Z
{

};
struct W
{
    operator Z();
};

int main()
{
    f(1u, 1l); //work
    f(W{}, Z{});
    f(Z{}, W{}); //and this work too
}

https://godbolt.org/g/ieuHTS

like image 31
Yankes Avatar answered Oct 24 '22 03:10

Yankes


It's certainly possible, just with a little delegation. You've made the problem pretty easy by specifying that you always want the inferred type to be the type of the first argument, so all we need to do is drop a little hint to the compiler.

template <class T>
void do_stuff_impl(T a, T b) {
    cout << "Doing some work..." << endl;
}

template <class T, class S>
void do_stuff(T a, S b) {
    do_stuff_impl<T>(a, b);
}

Now the user can call do_stuff with any two arguments, and C++ will try to implicitly cast the second argument to match the type of the first. If the cast isn't valid, you'll get a template instantiation error. On GCC, it says cannot convert ‘b’ (type ‘A’) to type ‘B’, which is pretty accurate and to the point. And any compiler worth its salt is going to be able to inline that delegated call, so there should be negligible overhead.

like image 7
Silvio Mayolo Avatar answered Oct 24 '22 04:10

Silvio Mayolo