Let's say we have a class like this with a user-defined deduction guide:
template<typename T, typename... Args>
struct Foo
{
Foo(Args&&...) { std::cout << "just Args: " << __PRETTY_FUNCTION__ << std::endl; }
Foo(Args&&..., T&&) { std::cout << "Args and T: " << __PRETTY_FUNCTION__ << std::endl; }
};
template<typename... Args>
Foo(Args&&...) -> Foo<Void, Args...>;
Now let's try to create an instance of this class: Foo foo { 10 };
. What would be the deduced template arguments and what constructor will be called?
After some experimentation turns out it depends on the compiler. Namely, gcc 7 and clang 6 (from trunk) seem to choose the automatic guide, instantiating T
with int
and Args
with an empty pack, hence the output is
Args and T: Foo<T, Args>::Foo(Args&& ..., T&&) [with T = int; Args = {}]
clang 5, on the other hand, chooses the user-defined guide:
just Args: Foo<Void, int>::Foo(Args &&...) [T = Void, Args = <int>]
Which choice is the right one, and how one might use the user-defined deduction guide in this case?
Full example available on wandbox.
Let's go from first principles. Trying to deduce from Foo{10}
involves doing overload resolution on this set:
template <typename T, typename... Args>
Foo<T, Args...> __f(Args&&... ); // ctor #1
template <typename T, typename... Args>
Foo<T, Args...> __f(Args&&..., T&&); // ctor #2
template <typename... Args>
Foo<Void, Args...> __f(Args&&... ); // deduction guide
In the function synthesized from the first constructor, T
is a non-deduced context. In the function synthesized from the second constructor, Args
is a non-deduced context. So neither are viable. The deduction guide is viable, so it's trivially the best viable candidate, so we end up with a Foo<Void, int>
.
Once we're there, we perform overload resolution again to pick a constructor. This is more straightforward, the first one is viable and the second isn't, so it should be invoked.
Any other behavior is a compiler bug (filed 83447).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With