可变参数推导指南不是由 g++ 采用,由 clang++ 采用 - 谁是正确的?
Variadic deduction guide not taken by g++, taken by clang++ - who is correct?
考虑以下代码:
template <typename... Types>
struct list
{
template <typename... Args>
list(Args...)
{
static_assert(sizeof...(Types) > 0);
}
};
template <typename... Args>
list(Args...) -> list<Args...>;
int main()
{
list l{0, 0.1, 'a'};
}
我希望 decltype(l)
是 list<int, double, char>
。不幸的是,g++ 7.2 和 g++ trunk 未能通过静态断言。 clang++ 5.0.0 和 clang++ trunk 编译并按预期工作。
这是 g++ 错误吗?或者为什么不应该在此处遵循推导指南?
在构造函数上添加 SFINAE 约束似乎提供了所需的行为:
template <typename... Args,
typename = std::enable_if_t<sizeof...(Args) == sizeof...(Types)>>
list(Args...)
{
static_assert(sizeof...(Types) > 0);
}
这是gcc bug 80871。问题是,我们最终得到了这组推导候选人:
template <class... Types, class... Args>
list<Types...> __f(Args... ); // constructor
template <class... Args>
list<Args...> __f(Args... ); // deduction-guide
两者都是有效的(Types...
在第一种情况下可以推断为空),但这里的调用应该是模棱两可的——两者都不比另一个更专业。 Types...
不参与这里的排序(类似于[temp.deduct.partial]/12). So the correct behavior is to proceed to the next tiebreaker, which favors deduction-guides中的例子。因此,这应该是一个list<int, double, char>
。
然而,gcc 的行为是有利于构造函数,因此 static_assert
触发器,因为 Types...
在那种情况下确实是空的。
考虑以下代码:
template <typename... Types>
struct list
{
template <typename... Args>
list(Args...)
{
static_assert(sizeof...(Types) > 0);
}
};
template <typename... Args>
list(Args...) -> list<Args...>;
int main()
{
list l{0, 0.1, 'a'};
}
我希望 decltype(l)
是 list<int, double, char>
。不幸的是,g++ 7.2 和 g++ trunk 未能通过静态断言。 clang++ 5.0.0 和 clang++ trunk 编译并按预期工作。
这是 g++ 错误吗?或者为什么不应该在此处遵循推导指南?
在构造函数上添加 SFINAE 约束似乎提供了所需的行为:
template <typename... Args,
typename = std::enable_if_t<sizeof...(Args) == sizeof...(Types)>>
list(Args...)
{
static_assert(sizeof...(Types) > 0);
}
这是gcc bug 80871。问题是,我们最终得到了这组推导候选人:
template <class... Types, class... Args>
list<Types...> __f(Args... ); // constructor
template <class... Args>
list<Args...> __f(Args... ); // deduction-guide
两者都是有效的(Types...
在第一种情况下可以推断为空),但这里的调用应该是模棱两可的——两者都不比另一个更专业。 Types...
不参与这里的排序(类似于[temp.deduct.partial]/12). So the correct behavior is to proceed to the next tiebreaker, which favors deduction-guides中的例子。因此,这应该是一个list<int, double, char>
。
然而,gcc 的行为是有利于构造函数,因此 static_assert
触发器,因为 Types...
在那种情况下确实是空的。