演绎指南和可变参数模板
Deduction guide and variadic templates
考虑以下代码:
#include <tuple>
#include <iostream>
template <class T>
struct custom_wrapper
{
template <class Arg>
custom_wrapper(Arg arg): data(arg) {}
T data;
};
template <class Arg>
custom_wrapper(Arg arg) -> custom_wrapper<Arg>;
template <class... T>
struct custom_tuple
{
template <class... Args>
custom_tuple(Args... args): data(args...) {}
std::tuple<T...> data;
};
template <class... Args>
custom_tuple(Args... args) -> custom_tuple<Args...>;
int main(int argc, char* argv[])
{
custom_wrapper<int> w1(42); // OK
custom_wrapper w2(42); // OK
custom_tuple<int> t1(42); // OK
custom_tuple t2(42); // Fails
return 0;
}
失败的行return在g++7下出现如下错误:
variadic_deduction_guide.cpp: In instantiation of 'custom_tuple<T>::custom_tuple(Args ...) [with Args = {int}; T = {}]':
variadic_deduction_guide.cpp:31:23: required from here
variadic_deduction_guide.cpp:19:45: error: no matching function for call to 'std::tuple<>::tuple(int&)'
custom_tuple(Args... args): data(args...) {}
这是正常现象还是编译器错误?
这是gcc bug 80871。下面是对为什么代码格式正确的解释(并且 clang 在决定 t2
是 custom_tuple<int>
时是正确的)。
弄清楚要做什么的过程
custom_tuple t2(42);
基本上涉及合成一堆函数并对它们执行重载解析。相关候选者是来自一个构造函数和推导指南的综合函数:
template <class... T, class... Args>
custom_tuple<T...> foo(Args... ); // the constructor
template <class... Args>
custom_tuple<Args...> foo(Args... ); // the deduction guide
从这一点开始,您可以根据 [temp.arg.explicit]/3:
对 "trailing parameter pack" 的解释来选择您自己的冒险
A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments. If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list <>
itself may also be omitted.
T...
没有尾随
这个案例很简单。我们只有一个可行的候选者(因为 T...
不可推导)——演绎指南候选者。我们将 Args...
推断为 {int}
,所以我们最终得到 custom_tuple<int>
。
T...
尾随
gcc 和 clang 实际上确实考虑了构造函数的推导成功。所以我们进入 [over.match.best]:
的决胜局
Given these definitions, a viable function F1
is defined to be a better function than another viable function F2
if [...]
F1
and F2
are function template specializations, and the function template for F1
is more specialized than the template for F2
according to the partial ordering rules described in [temp.func.order], or, if not that,
F1
is generated from a deduction-guide ([over.match.class.deduct]) and F2
is not, or, if not that, [...]
出于部分排序的目的,relevant types are just those which correspond to function parameters, and we're allowed to ignore unused template parameters,因此两个函数模板都不被认为比另一个更专业。
这让我们更喜欢演绎指南,这是整个过程中最简单的一步。我们将 Args...
推断为 {int}
,所以我们最终得到 custom_tuple<int>
。
无论哪种方式,custom_tuple<int>
都是正确的决定。
考虑以下代码:
#include <tuple>
#include <iostream>
template <class T>
struct custom_wrapper
{
template <class Arg>
custom_wrapper(Arg arg): data(arg) {}
T data;
};
template <class Arg>
custom_wrapper(Arg arg) -> custom_wrapper<Arg>;
template <class... T>
struct custom_tuple
{
template <class... Args>
custom_tuple(Args... args): data(args...) {}
std::tuple<T...> data;
};
template <class... Args>
custom_tuple(Args... args) -> custom_tuple<Args...>;
int main(int argc, char* argv[])
{
custom_wrapper<int> w1(42); // OK
custom_wrapper w2(42); // OK
custom_tuple<int> t1(42); // OK
custom_tuple t2(42); // Fails
return 0;
}
失败的行return在g++7下出现如下错误:
variadic_deduction_guide.cpp: In instantiation of 'custom_tuple<T>::custom_tuple(Args ...) [with Args = {int}; T = {}]':
variadic_deduction_guide.cpp:31:23: required from here
variadic_deduction_guide.cpp:19:45: error: no matching function for call to 'std::tuple<>::tuple(int&)'
custom_tuple(Args... args): data(args...) {}
这是正常现象还是编译器错误?
这是gcc bug 80871。下面是对为什么代码格式正确的解释(并且 clang 在决定 t2
是 custom_tuple<int>
时是正确的)。
弄清楚要做什么的过程
custom_tuple t2(42);
基本上涉及合成一堆函数并对它们执行重载解析。相关候选者是来自一个构造函数和推导指南的综合函数:
template <class... T, class... Args>
custom_tuple<T...> foo(Args... ); // the constructor
template <class... Args>
custom_tuple<Args...> foo(Args... ); // the deduction guide
从这一点开始,您可以根据 [temp.arg.explicit]/3:
对 "trailing parameter pack" 的解释来选择您自己的冒险A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments. If all of the template arguments can be deduced, they may all be omitted; in this case, the empty template argument list
<>
itself may also be omitted.
T...
没有尾随
这个案例很简单。我们只有一个可行的候选者(因为 T...
不可推导)——演绎指南候选者。我们将 Args...
推断为 {int}
,所以我们最终得到 custom_tuple<int>
。
T...
尾随
gcc 和 clang 实际上确实考虑了构造函数的推导成功。所以我们进入 [over.match.best]:
的决胜局Given these definitions, a viable function
F1
is defined to be a better function than another viable functionF2
if [...]
F1
andF2
are function template specializations, and the function template forF1
is more specialized than the template forF2
according to the partial ordering rules described in [temp.func.order], or, if not that,F1
is generated from a deduction-guide ([over.match.class.deduct]) andF2
is not, or, if not that, [...]
出于部分排序的目的,relevant types are just those which correspond to function parameters, and we're allowed to ignore unused template parameters,因此两个函数模板都不被认为比另一个更专业。
这让我们更喜欢演绎指南,这是整个过程中最简单的一步。我们将 Args...
推断为 {int}
,所以我们最终得到 custom_tuple<int>
。
无论哪种方式,custom_tuple<int>
都是正确的决定。