我们假设我们有一个类似于此类的用户定义的演绎指南:
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...>;
现在让我们尝试创建此类的实例:Foo foo { 10 };
。什么是推导出的模板参数以及将调用哪个构造函数?
经过一些实验后,它取决于编译器。也就是说,gcc 7和clang 6(来自主干)似乎选择自动指南,用T
和int
实例化Args
空包,因此输出
Args and T: Foo<T, Args>::Foo(Args&& ..., T&&) [with T = int; Args = {}]
另一方面,clang 5选择用户定义的指南:
just Args: Foo<Void, int>::Foo(Args &&...) [T = Void, Args = <int>]
哪种选择是正确的,在这种情况下如何使用用户定义的演绎指南?
wandbox上的完整示例。
答案 0 :(得分:3)
让我们从第一原则出发。试图从Foo{10}
推导出涉及对此集合进行重载解析:
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
在从第一个构造函数合成的函数中,T
是一个非推导的上下文。在从第二个构造函数合成的函数中,Args
是非推导的上下文。所以两者都不可行。扣除指南是可行的,因此它是最有可行的候选人,所以我们最终得到Foo<Void, int>
。
一旦我们在那里,我们再次执行重载决策以选择构造函数。这更直截了当,第一个是可行的,第二个是不可行的,所以应该调用它。