Konstantin Vladimirov
Konstantin Vladimirov

Reputation: 7009

Why template argument deduction fails?

Minimized example:

template <typename T, int N>
struct Deducer {
    Deducer(int) {}
};

template <typename T, int N = 1>
void foo(Deducer<T, N> d){}

int main() {
    foo<char>(345);
}

godbolt example

Yields error

candidate template ignored: could not match 'Deducer<char, N>' against 'int'

Why compiler ignores implicit cast?

If any simple workaround possible here?

I can think about two options:

(1) Specify all template parameters (not an option for me, real case have many of them, I want deduction) (2) Write intermediate function like this:

template <typename T, int N = 1>
void foo_step(int d){ foo<T, N>(d); }

Not an option either, I have large number of arguments.

Any ideas?

Upvotes: 1

Views: 79

Answers (2)

Jarod42
Jarod42

Reputation: 218323

N is deducible in

template <typename T, int N = 1> void foo(Deducer<T, N> d)

So default value = 1 is mostly useless.

If you want to force to call the method like:

foo<char>(345);
foo<char, 42>(345);

You might do:

// in C++20, std::type_identity might be used instead:
template <typename T> struct non_deducible { using type = T; };
template <typename T> using non_deducible_t = typename non_deducible<T>::type;

template <typename T, int N = 1> void foo(non_deducible_t<Deducer<T, N>> d);

But you no longer can do:

foo(Deducer<char, 42>());

Upvotes: 3

theWiseBro
theWiseBro

Reputation: 1529

As per this:

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.

You can try having something like this:

template <typename T, typename U, int N = 1>
void foo(U&& u)
{
    foo(Deducer<T,N>(std::forward<U>(u)));
}

Upvotes: 2

Related Questions